diff --git a/.codecov.yml b/.codecov.yml index 72dcaaf4c845..e59580d4ee72 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -2,10 +2,3 @@ codecov: require_ci_to_pass: no max_report_age: off -fixes: - - "ballerina/lang&0046*/*/::langlib/lang.*/src/main/ballerina/" - -ignore: - - "**/tests" - - "tests/language-server-simulator" - diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 79680dd37886..426203e9c9e0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -3,18 +3,31 @@ # See: https://help.github.com/articles/about-codeowners/ +* @gimantha + # Components -/compiler/ @sameerajayasoma @hasithaa -/langlib/ @sameerajayasoma @hasithaa -/semtypes/ @sameerajayasoma @hasithaa -/language-server/ @mohanvive @IMS94 -/ballerina-shell/ @mohanvive +/compiler/ @sameerajayasoma @hasithaa @gimantha @MaryamZi +/ballerina-shell/ @KavinduZoysa +/build-config/ @keizer619 /bvm/ @warunalakshitha -/observelib/ @nadundesilva -/cli/ @hevayo -/distribution/ @hevayo -/misc/ @hevayo -/project-api/ @hevayo @sameerajayasoma +/cli/ @azinneera +/distribution/ @keizer619 +/gradle/ @keizer619 +/langlib/ @sameerajayasoma @hasithaa @gimantha @MaryamZi +/semtypes/ @gimantha @MaryamZi +/language-server/ @KavinduZoysa +/misc/ballerina-bindgen/ @warunalakshitha +/misc/compiler-plugins/ @azinneera +/misc/debug-adapter/ @NipunaRanasinghe +/misc/docerina/ @keizer619 +/misc/identifier-util/ @warunalakshitha +/misc/json-to-record-converter/ @NipunaRanasinghe +/misc/semver-checker/ @NipunaRanasinghe +/misc/testerina/ @azinneera @Dilhasha +/misc/xml-to-record-converter/ @NipunaRanasinghe +/project-api/ @azinneera @sameerajayasoma +/performance/ @anuruddhal +/tests/ @gimantha @MaryamZi @KavinduZoysa @warunalakshitha @azinneera # CODEOWNERS file -/.github/CODEOWNERS @sameerajayasoma @hasithaa @anupama-pathirage @warunalakshitha @mohanvive @manuranga @hevayo +/.github/CODEOWNERS @sameerajayasoma @gimantha @MaryamZi @hasithaa diff --git a/.github/workflows/automate_issue_labels.yml b/.github/workflows/automate_issue_labels.yml index 2b677eb3bab1..180aeef04c82 100644 --- a/.github/workflows/automate_issue_labels.yml +++ b/.github/workflows/automate_issue_labels.yml @@ -8,7 +8,7 @@ jobs: Add-label: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Check for Type label inclusion if: ${{ !(contains(join(github.event.issue.labels.*.name, ','), 'Type/')) }} @@ -53,13 +53,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} ISSUE: ${{ github.event.issue.number }} - - name: Check for APIDocs related issue - if: ${{ contains(github.event.issue.body, '-> API Docs') }} - run: gh issue transfer $ISSUE "ballerina-platform/ballerina-dev-tools" - env: - GITHUB_TOKEN: ${{ secrets.BALLERINA_BOT_TOKEN }} - ISSUE: ${{ github.event.issue.number }} - - name: Check for Debugger related issue if: ${{ contains(github.event.issue.body, '-> Debugger') }} run: | diff --git a/.github/workflows/daily_build.yml b/.github/workflows/daily_build.yml index 4547fb733abe..f861e10a339f 100644 --- a/.github/workflows/daily_build.yml +++ b/.github/workflows/daily_build.yml @@ -9,14 +9,14 @@ jobs: ubuntu_build: name: Build with tests on Ubuntu runs-on: ubuntu-latest - timeout-minutes: 75 + timeout-minutes: 120 steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17.0.7' @@ -25,7 +25,7 @@ jobs: run: git submodule update --init - name: Cache Gradle packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ github.sha }} @@ -65,12 +65,12 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17.0.7' @@ -79,14 +79,14 @@ jobs: run: git submodule update --init - name: Cache SonarCloud packages - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - name: Cache Gradle packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ github.sha }} diff --git a/.github/workflows/daily_spec_conformance_test_runner.yml b/.github/workflows/daily_spec_conformance_test_runner.yml index 37f1f6f6215f..5b19e8f092db 100644 --- a/.github/workflows/daily_spec_conformance_test_runner.yml +++ b/.github/workflows/daily_spec_conformance_test_runner.yml @@ -13,12 +13,12 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: spec-conformance-test-runner - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: "temurin" java-version: "17" @@ -35,7 +35,7 @@ jobs: ./gradlew ballerina-spec-conformance-tests:test --configure-on-demand --no-daemon - name: Spec conformance report - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: spec-conformance-test-report diff --git a/.github/workflows/fossa_scan.yml b/.github/workflows/fossa_scan.yml index 0444ed52540f..eeb4ac0fb43b 100644 --- a/.github/workflows/fossa_scan.yml +++ b/.github/workflows/fossa_scan.yml @@ -5,7 +5,7 @@ jobs: fossa-scan: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: fossas/fossa-action@main with: api-key: ${{secrets.FOSSA_APIKEY}} diff --git a/.github/workflows/fossa_scan_1.2.x.yml b/.github/workflows/fossa_scan_1.2.x.yml index ad18d3b44af7..5b4917ff175a 100644 --- a/.github/workflows/fossa_scan_1.2.x.yml +++ b/.github/workflows/fossa_scan_1.2.x.yml @@ -5,7 +5,7 @@ jobs: fossa-scan: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: fossas/fossa-action@main with: api-key: ${{secrets.FOSSA_APIKEY}} diff --git a/.github/workflows/nightly_publish_timestamped_release.yml b/.github/workflows/nightly_publish_timestamped_release.yml index 6cf915c37084..653d06697230 100644 --- a/.github/workflows/nightly_publish_timestamped_release.yml +++ b/.github/workflows/nightly_publish_timestamped_release.yml @@ -17,12 +17,12 @@ jobs: if: github.repository_owner == 'ballerina-platform' steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ matrix.branch }} - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17.0.7' @@ -45,7 +45,7 @@ jobs: publishUser: ${{ secrets.BALLERINA_BOT_USERNAME }} publishPAT: ${{ secrets.BALLERINA_BOT_TOKEN }} run: | - ./gradlew clean build -x createJavadoc --scan --continue --rerun-tasks + ./gradlew clean build -x javadoc --scan --continue --rerun-tasks ./gradlew publish ./gradlew createCodeCoverageReport curl -X POST \ @@ -61,6 +61,6 @@ jobs: }" - name: Generate Codecov Report - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: files: ./.jacoco/reports/jacoco/report.xml diff --git a/.github/workflows/observe_package_push.yaml b/.github/workflows/observe_package_push.yaml index 51506d3f68aa..7740cd92010a 100644 --- a/.github/workflows/observe_package_push.yaml +++ b/.github/workflows/observe_package_push.yaml @@ -12,13 +12,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Checkout Tag run: git checkout ${{ github.event.inputs.repoTag }} - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17.0.7' diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml index e62caced9c86..bf1d51fc6df5 100644 --- a/.github/workflows/publish_release.yml +++ b/.github/workflows/publish_release.yml @@ -8,9 +8,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17.0.7' diff --git a/.github/workflows/publish_timestamped_release.yml b/.github/workflows/publish_timestamped_release.yml index bd39a4f4add9..489a1168d272 100644 --- a/.github/workflows/publish_timestamped_release.yml +++ b/.github/workflows/publish_timestamped_release.yml @@ -14,10 +14,10 @@ jobs: if: github.repository_owner == 'ballerina-platform' steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17.0.7' @@ -44,11 +44,11 @@ jobs: publishUser: ${{ secrets.BALLERINA_BOT_USERNAME }} publishPAT: ${{ secrets.BALLERINA_BOT_TOKEN }} run: | - ./gradlew clean build -x check -x test -x createJavadoc --scan --continue --rerun-tasks + ./gradlew clean build -x check -x test -x javadoc --scan --continue --rerun-tasks ./gradlew publish ./gradlew createCodeCoverageReport - name: Generate Codecov Report - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: files: ./.jacoco/reports/jacoco/report.xml diff --git a/.github/workflows/pull_request_full_build.yml b/.github/workflows/pull_request_full_build.yml index cdc5746c7353..1e24c1eb6cb9 100644 --- a/.github/workflows/pull_request_full_build.yml +++ b/.github/workflows/pull_request_full_build.yml @@ -16,10 +16,10 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17.0.7' @@ -32,17 +32,18 @@ jobs: id: lang-version run: | VERSION=$((grep -w "version" | cut -d= -f2) < gradle.properties) - echo "::set-output name=version::$VERSION" + echo "version=$VERSION" >> $GITHUB_OUTPUT - name: Build ballerina-lang run: | ./gradlew clean build -x check publishToMavenLocal --stacktrace --scan - name: Archive Lang Artifacts - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: Ballerina Lang Artifacts path: ~/.m2/ + include-hidden-files: true outputs: lang_version: ${{ steps.lang-version.outputs.version }} @@ -62,20 +63,20 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v2 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17.0.7' - name: Setup NodeJs - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 10.22.1 - name: Download Ballerina Lang Artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: Ballerina Lang Artifacts path: ~/.m2/ @@ -127,18 +128,18 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: 'ballerina-platform/ballerina-distribution' - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17.0.7' - name: Download Ballerina Lang Artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: Ballerina Lang Artifacts path: ~/.m2/ diff --git a/.github/workflows/pull_request_ubuntu_build.yml b/.github/workflows/pull_request_ubuntu_build.yml index 5bdf8e1e7fee..d6e9920c30ee 100644 --- a/.github/workflows/pull_request_ubuntu_build.yml +++ b/.github/workflows/pull_request_ubuntu_build.yml @@ -27,10 +27,10 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17.0.7' @@ -39,7 +39,7 @@ jobs: run: git submodule update --init - name: Cache Gradle packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ github.sha }} @@ -69,7 +69,7 @@ jobs: - name: Generate Codecov Report if: github.event_name == 'pull_request' - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 with: files: ./.jacoco/reports/jacoco/report.xml @@ -83,12 +83,12 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17.0.7' @@ -97,14 +97,14 @@ jobs: run: git submodule update --init - name: Cache SonarCloud packages - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - name: Cache Gradle packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ github.sha }} diff --git a/.github/workflows/pull_request_windows_build.yml b/.github/workflows/pull_request_windows_build.yml index 4f42987df8a5..8eca0c156228 100644 --- a/.github/workflows/pull_request_windows_build.yml +++ b/.github/workflows/pull_request_windows_build.yml @@ -26,34 +26,43 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17.0.7' - name: configure Pagefile - uses: al-cheb/configure-pagefile-action@7e234852c937eea04d6ee627c599fb24a5bfffee + uses: al-cheb/configure-pagefile-action@v1.4 with: minimum-size: 8GB maximum-size: 16GB - disk-root: "D:" + disk-root: "C:" - name: Initialize sub-modules run: git submodule update --init - name: Cache Gradle packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: ${{ runner.os }}-gradle + - name: Setup GraalVM + uses: graalvm/setup-graalvm@v1 + with: + java-version: '17.0.7' + distribution: 'graalvm' + components: 'native-image' + github-token: ${{ secrets.GITHUB_TOKEN }} + set-java-home: 'false' + - name: Build with Gradle env: packageUser: ${{ github.actor }} packagePAT: ${{ secrets.GITHUB_TOKEN }} - run: ./gradlew.bat build --continue -x :ballerina-lang:test -x :jballerina-integration-test:test -x :ballerina-shell:shell-cli:test -x :ballerina-cli:test -x createJavadoc --stacktrace -scan --console=plain --no-daemon --no-parallel + run: ./gradlew.bat build --continue -x :ballerina-lang:test -x :jballerina-integration-test:test -x javadoc --stacktrace -scan --console=plain --no-daemon --no-parallel diff --git a/.github/workflows/push_master.yml b/.github/workflows/push_master.yml index a527a28520a9..962eef94076a 100644 --- a/.github/workflows/push_master.yml +++ b/.github/workflows/push_master.yml @@ -17,10 +17,10 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17.0.7' @@ -29,12 +29,21 @@ jobs: run: git submodule update --init - name: Cache Gradle packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ github.sha }} restore-keys: ${{ runner.os }}-gradle + - name: Setup GraalVM + uses: graalvm/setup-graalvm@v1 + with: + java-version: '17.0.7' + distribution: 'graalvm' + components: 'native-image' + github-token: ${{ secrets.GITHUB_TOKEN }} + set-java-home: 'false' + - name: Build with Gradle run: | export DISPLAY=':99.0' @@ -45,40 +54,49 @@ jobs: windows_build: name: Build with some tests on Windows runs-on: windows-latest - timeout-minutes: 120 + timeout-minutes: 150 concurrency: group: ${{ github.head_ref }}-windows cancel-in-progress: true steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17.0.7' - name: configure Pagefile - uses: al-cheb/configure-pagefile-action@7e234852c937eea04d6ee627c599fb24a5bfffee + uses: al-cheb/configure-pagefile-action@v1.4 with: minimum-size: 8GB maximum-size: 16GB - disk-root: "D:" + disk-root: "C:" - name: Initialize sub-modules run: git submodule update --init - name: Cache Gradle packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: ${{ runner.os }}-gradle + - name: Setup GraalVM + uses: graalvm/setup-graalvm@v1 + with: + java-version: '17.0.7' + distribution: 'graalvm' + components: 'native-image' + github-token: ${{ secrets.GITHUB_TOKEN }} + set-java-home: 'false' + - name: Build with Gradle - run: ./gradlew.bat build --continue -x :ballerina-lang:test -x :jballerina-integration-test:test -x :ballerina-shell:shell-cli:test -x :jballerina-debugger-integration-test:test -x createJavadoc --stacktrace -scan --console=plain --no-daemon --no-parallel + run: ./gradlew.bat build --continue -x :ballerina-lang:test -x :jballerina-integration-test:test -x :jballerina-debugger-integration-test:test -x javadoc --stacktrace -scan --console=plain --no-daemon --no-parallel sonarcloud_scan: @@ -91,12 +109,12 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17.0.7' @@ -105,14 +123,14 @@ jobs: run: git submodule update --init - name: Cache SonarCloud packages - uses: actions/cache@v1 + uses: actions/cache@v4 with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - name: Cache Gradle packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ github.sha }} diff --git a/.github/workflows/stale_check.yml b/.github/workflows/stale_check.yml deleted file mode 100644 index 8763360ad1bc..000000000000 --- a/.github/workflows/stale_check.yml +++ /dev/null @@ -1,19 +0,0 @@ -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 index 183d3118e019..e9bee7d70e53 100644 --- a/.github/workflows/trivy-scan.yml +++ b/.github/workflows/trivy-scan.yml @@ -11,9 +11,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '17.0.7' @@ -21,7 +21,7 @@ jobs: - name: Initialize sub-modules run: git submodule update --init - name: Cache Gradle packages - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ github.sha }} diff --git a/.travis.yml b/.travis.yml index 925525ef309d..d9ea01a59614 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,13 +36,13 @@ jobs: - export PATH="$PATH;$JAVA_HOME\\bin" script: - while sleep 9m; do echo "=====[ $SECONDS seconds still running ]====="; done & - - ./gradlew.bat build -x test -x createJavadoc --stacktrace -scan --console=plain --no-daemon + - ./gradlew.bat build -x test -x javadoc --stacktrace -scan --console=plain --no-daemon # Killing background sleep loop - kill %1 name: "Build without tests - Windows" - script: - while sleep 9m; do echo "=====[ $SECONDS seconds still running ]====="; done & - - ./gradlew build -x test -x createJavadoc --stacktrace -scan --console=plain --no-daemon + - ./gradlew build -x test -x javadoc --stacktrace -scan --console=plain --no-daemon # Killing background sleep loop - kill %1 name: "Build without tests - Linux" @@ -59,7 +59,7 @@ jobs: name: "Run Build + tests (without integration) - Linux" script: - while sleep 9m; do echo "=====[ $SECONDS seconds still running ]====="; done & - - ./gradlew build -x :jballerina-integration-test:test -x :testerina-integration-test:test -x createJavadoc --stacktrace -scan --console=plain --no-daemon + - ./gradlew build -x :jballerina-integration-test:test -x :testerina-integration-test:test -x javadoc --stacktrace -scan --console=plain --no-daemon # Killing background sleep loop - kill %1 os: linux @@ -79,7 +79,7 @@ jobs: - script: - while sleep 9m; do echo "=====[ $SECONDS seconds still running ]====="; done & # TODO enable tests for all projects - - ./gradlew.bat build -Dorg.gradle.parallel=false -x :ballerina-packerina:test -x :ballerina-lang:test -x :jballerina-unit-test:test -x :jballerina-integration-test:test -x createJavadoc --stacktrace -scan --console=plain --no-daemon + - ./gradlew.bat build -Dorg.gradle.parallel=false -x :ballerina-packerina:test -x :ballerina-lang:test -x :jballerina-unit-test:test -x :jballerina-integration-test:test -x javadoc --stacktrace -scan --console=plain --no-daemon # Killing background sleep loop - kill %1 name: "Tests - windows" @@ -92,7 +92,7 @@ jobs: - export PATH="$PATH;$JAVA_HOME\\bin" - script: - while sleep 9m; do echo "=====[ $SECONDS seconds still running ]====="; done & - - ./gradlew :jballerina-integration-test:test :testerina-integration-test:test -x createJavadoc --stacktrace -scan --console=plain --no-daemon + - ./gradlew :jballerina-integration-test:test :testerina-integration-test:test -x javadoc --stacktrace -scan --console=plain --no-daemon # Killing background sleep loop - kill %1 os: linux diff --git a/Jenkinsfile b/Jenkinsfile index fc6a689f940d..0c7a3384f563 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -7,7 +7,7 @@ node('COMPONENT_ECS') { git clone https://github.com/ballerina-platform/ballerina-lang cd ballerina-lang/ #Temporary javadoc creation and spot bug check will be skipped - ./gradlew build --console=plain --stacktrace -scan -x createJavadoc -x spotbugsMain -x openapi-ballerina:ballerina-to-openapi-generator:test -x test -x check + ./gradlew build --console=plain --stacktrace -scan -x javadoc -x spotbugsMain -x openapi-ballerina:ballerina-to-openapi-generator:test -x test -x check ./gradlew publish """ } diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 3a35ec4479ca..a104f39159d8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -17,5 +17,5 @@ jobs: path: $(GRADLE_USER_HOME) displayName: Gradle build cache - script: | - ./gradlew build -Dorg.gradle.parallel=false -x :language-server:language-server-core:test -x :ballerina-packerina:test -x :ballerina-lang:test -x :ballerina-http:test -x :ballerina-file:test -x :ballerina-task:test -x :ballerina-kafka:test -x :jballerina-unit-test:test -x :jballerina-integration-test:test -x createJavadoc --stacktrace -scan --console=plain --no-daemon + ./gradlew build -Dorg.gradle.parallel=false -x :language-server:language-server-core:test -x :ballerina-packerina:test -x :ballerina-lang:test -x :ballerina-http:test -x :ballerina-file:test -x :ballerina-task:test -x :ballerina-kafka:test -x :jballerina-unit-test:test -x :jballerina-integration-test:test -x javadoc --stacktrace -scan --console=plain --no-daemon displayName: 'Ballerina Windows Build' diff --git a/ballerina-shell/README.md b/ballerina-shell/README.md index 67cce916984d..69470069459f 100644 --- a/ballerina-shell/README.md +++ b/ballerina-shell/README.md @@ -16,12 +16,12 @@ The Ballerina-shell tool is an interactive tool for learning the Ballerina progr The project is implemented in three base modules. - **shell-rt** - Module including runtime dependencies for ballerina programs generated. You may find the source code for this - module [here](shell-rt). + module [here](modules/shell-rt). - **shell-core** - Module including all the base evaluation classes. This has all the base components to evaluate and run a string. All other components are built on top of this module. You may find the source code for this - module [here](shell-core). + module [here](modules/shell-core). - **shell-cli** - A command-line interface built on top of shell. Includes multi-line inputs, color-coded outputs, - keyword-based auto-completion, etc... You may find the source code for this module [here](shell-cli). + keyword-based auto-completion, etc... You may find the source code for this module [here](modules/shell-cli). ## Known Issues @@ -103,7 +103,7 @@ The project is implemented in three base modules. ## Implementation -For implementation details please refer [this](shell-core/README.md). +For implementation details please refer [this](modules/shell-core/README.md). ## Building diff --git a/ballerina-shell/modules/shell-cli/build.gradle b/ballerina-shell/modules/shell-cli/build.gradle index a10e54d4dbec..fb3044662bcd 100644 --- a/ballerina-shell/modules/shell-cli/build.gradle +++ b/ballerina-shell/modules/shell-cli/build.gradle @@ -16,8 +16,10 @@ * under the License. */ -apply from: "$rootDir/gradle/javaProject.gradle" -apply from: "$rootDir/gradle/ballerinaLangLibLoad.gradle" +plugins { + id 'javaProject' + id 'ballerinaLangLibLoad' +} description = 'Ballerina - Ballerina Shell CLI' @@ -26,21 +28,19 @@ group = 'io.ballerina' dependencies { implementation project(":ballerina-shell:shell-core") implementation project(':ballerina-parser') - implementation("org.jline:jline:${project.jlineVersion}") + implementation libs.jline implementation project(':ballerina-lang') implementation project(':ballerina-tools-api') - testImplementation('org.testng:testng') - implementation 'com.google.code.gson:gson:2.10.1' + testImplementation libs.testng + implementation libs.gson } compileJava { doFirst { options.compilerArgs += [ - "-Aproject=${project.group}/${project.name}", - '--module-path', classpath.asPath, + "-Aproject=${project.group}/${project.name}" ] - classpath = files() } } @@ -51,13 +51,13 @@ test { } def mainCliClass = 'io.ballerina.shell.cli.ReplShellApplication' -task run(type: JavaExec) { - main = mainCliClass +tasks.register('run', JavaExec) { + mainClass = mainCliClass standardInput = System.in classpath = sourceSets.main.runtimeClasspath } -task fatJar(type: Jar) { +tasks.register('fatJar', Jar) { duplicatesStrategy = DuplicatesStrategy.EXCLUDE manifest { attributes 'Main-Class': mainCliClass } from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } diff --git a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/BallerinaShell.java b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/BallerinaShell.java index f2e9edd0db00..3eb03d4eb1b4 100644 --- a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/BallerinaShell.java +++ b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/BallerinaShell.java @@ -299,7 +299,7 @@ public void importModules(ModuleImporter moduleImporter, List modules) { terminal.info(module); } - if (requiredModules.size() > 0) { + if (!requiredModules.isEmpty()) { terminal.info("\nFollowing undefined modules can be imported."); int moduleCount = 1; for (String module : requiredModules) { @@ -323,7 +323,7 @@ public void importModules(ModuleImporter moduleImporter, List modules) { } } - if (missingModules.size() > 0) { + if (!missingModules.isEmpty()) { terminal.error("\nFound following missing module(s)."); for (String missingModule : missingModules) { terminal.error(missingModule); @@ -378,7 +378,7 @@ public boolean isContainsUndefinedModules(Collection diagnostics) { private void executeChanges(String source, Collection diagnostics) { ModuleImporter moduleImporter = new ModuleImporter(); List modules = moduleImporter.undefinedModules(diagnostics); - if (modules.size() > 0) { + if (!modules.isEmpty()) { importModules(moduleImporter, modules); try { terminal.println(""); diff --git a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/ReplShellApplication.java b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/ReplShellApplication.java index c64ca77f276b..eb0880b6455b 100644 --- a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/ReplShellApplication.java +++ b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/ReplShellApplication.java @@ -38,7 +38,11 @@ * * @since 2.0.0 */ -public class ReplShellApplication { +public final class ReplShellApplication { + + private ReplShellApplication() { + } + /** * Executes the repl shell. * diff --git a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/HelpCommand.java b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/HelpCommand.java index 848f40cb2316..90ca1dd8c15b 100644 --- a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/HelpCommand.java +++ b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/HelpCommand.java @@ -73,8 +73,8 @@ public void run(String... args) { } else { try { ballerinaShell.outputInfo(NEW_LINE + bbeHelpProvider.getDescription(topic) - .replaceAll(TAGS, EMPTY_STRING)); - ballerinaShell.outputInfo(URL_PREFIX + URL + topic.replaceAll(" ", "-")); + .replace(TAGS, EMPTY_STRING)); + ballerinaShell.outputInfo(URL_PREFIX + URL + topic.replace(" ", "-")); } catch (HelpProviderException e) { ballerinaShell.outputError(NEW_LINE + "Can not find the topic : " + topic + NEW_LINE + NEW_LINE + diff --git a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/BbeHelpProvider.java b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/BbeHelpProvider.java index 3128b20510da..49d7d419bf96 100644 --- a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/BbeHelpProvider.java +++ b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/BbeHelpProvider.java @@ -21,7 +21,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; -import java.nio.file.Paths; +import java.nio.file.Path; import java.util.Arrays; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -54,7 +54,7 @@ public String getDescription(String topic) throws HelpProviderException { private static String readFileAsString(String file) throws HelpProviderException { String content; try { - content = Files.readString(Paths.get(file)); + content = Files.readString(Path.of(file)); } catch (IOException e) { throw new HelpProviderException("Error occurred while executing the command"); } diff --git a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/BbeRecord.java b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/BbeRecord.java index 2e9be6cd2830..2443007f7aa9 100644 --- a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/BbeRecord.java +++ b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/BbeRecord.java @@ -23,11 +23,11 @@ */ public class BbeRecord { - private String name; - private String url; - private String verifyBuild; - private String verifyOutput; - private String isLearnByExample; + private final String name; + private final String url; + private final String verifyBuild; + private final String verifyOutput; + private final String isLearnByExample; public BbeRecord(String name, String url, String verifyBuild, String verifyOutput, String isLearnByExample) { this.name = name; diff --git a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/BbeTitle.java b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/BbeTitle.java index 5f84472543f9..0794160832dc 100644 --- a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/BbeTitle.java +++ b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/BbeTitle.java @@ -25,10 +25,10 @@ */ public class BbeTitle { - private String title; - private String column; - private String category; - private BbeRecord[] samples; + private final String title; + private final String column; + private final String category; + private final BbeRecord[] samples; public BbeTitle(String title, String column, String category, BbeRecord[] samples) { this.title = title; diff --git a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/BbeTopicsProvider.java b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/BbeTopicsProvider.java index d76323f837eb..a72413ff08ff 100644 --- a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/BbeTopicsProvider.java +++ b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/BbeTopicsProvider.java @@ -24,7 +24,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; -import java.nio.file.Paths; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -41,7 +41,7 @@ public class BbeTopicsProvider extends DiagnosticReporter { private static final String BBE_FILE = "index.json"; private static final String TOPICS = "topics"; - private final List topicList;; + private final List topicList; private static BbeTopicsProvider bbeTopicsProvider = null; private BbeTopicsProvider() { @@ -66,7 +66,7 @@ private void populateTopicList() { Stream sampleList = Arrays.stream(samples); sampleList.forEach((bbeRecordElement) -> { if (bbeRecordElement != null) { - topicList.add(bbeRecordElement.getUrl().replaceAll("-", " ")); + topicList.add(bbeRecordElement.getUrl().replace("-", " ")); } }); } @@ -88,7 +88,7 @@ public List getTopicList() { private String readFileAsString(String file) { String content = null; try { - content = Files.readString(Paths.get(file)); + content = Files.readString(Path.of(file)); } catch (IOException e) { addDebugDiagnostic("Error loading the file : " + e.getMessage()); } diff --git a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/HelpProvider.java b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/HelpProvider.java index 1858577a75aa..175cab2bc827 100644 --- a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/HelpProvider.java +++ b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/handlers/help/HelpProvider.java @@ -30,7 +30,6 @@ public interface HelpProvider { * * @param args All the arguments given by requester. * @param output Builder to append output. - * @throws HelpProviderException If fetching help failed. */ - void getTopic(String[] args, StringBuilder output) throws HelpProviderException; + void getTopic(String[] args, StringBuilder output); } diff --git a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/jline/JlineBallerinaParser.java b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/jline/JlineBallerinaParser.java index 29ab31692ad2..ae2ecf99b717 100644 --- a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/jline/JlineBallerinaParser.java +++ b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/jline/JlineBallerinaParser.java @@ -69,7 +69,7 @@ public ParsedLine parse(String line, int cursor, ParseContext context) throws Sy } // Add left-over from last word - if (currentWord.length() > 0 || cursor == line.length()) { + if (!currentWord.isEmpty() || cursor == line.length()) { words.add(currentWord.toString()); } // Update indices and cursors diff --git a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/jline/JlineTerminalAdapter.java b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/jline/JlineTerminalAdapter.java index c37e27a58b17..9647488fb57f 100644 --- a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/jline/JlineTerminalAdapter.java +++ b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/jline/JlineTerminalAdapter.java @@ -26,6 +26,8 @@ import org.jline.utils.AttributedStringBuilder; import org.jline.utils.AttributedStyle; +import java.io.PrintWriter; + /** * Terminal adapter which encapsulates Jline. * @@ -56,10 +58,12 @@ public String readLine(String prefix, String postfix) throws ShellExitException } } + @SuppressWarnings("resource") @Override public void println(String text) { - lineReader.getTerminal().writer().println(text); - lineReader.getTerminal().writer().flush(); + PrintWriter writer = lineReader.getTerminal().writer(); + writer.println(text); + writer.flush(); } @Override diff --git a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/jline/parser/ParserStateMachine.java b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/jline/parser/ParserStateMachine.java index 6bbfeb773894..d17cdc75b0a5 100644 --- a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/jline/parser/ParserStateMachine.java +++ b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/jline/parser/ParserStateMachine.java @@ -18,9 +18,10 @@ package io.ballerina.shell.cli.jline.parser; +import java.util.ArrayDeque; +import java.util.Deque; import java.util.Map; import java.util.Set; -import java.util.Stack; /** * State machine implementation for ballerina parser. @@ -65,12 +66,12 @@ public class ParserStateMachine { CLOSE_PAREN, OPEN_PAREN, CLOSE_SQ_BR, OPEN_SQ_BR); - private final Stack stack; + private final Deque stack; private ParserState state; public ParserStateMachine() { this.state = ParserState.NORMAL; - this.stack = new Stack<>(); + this.stack = new ArrayDeque<>(); } public void feed(char character) { @@ -138,9 +139,9 @@ private void normalStateOrAfterOperator(char character) { case CLOSE_CURLY: case CLOSE_PAREN: case CLOSE_SQ_BR: - if (!stack.empty() && OPEN_BRACKETS.get(character).equals(stack.peek())) { + if (!stack.isEmpty() && OPEN_BRACKETS.get(character).equals(stack.peek())) { stack.pop(); - if (!stack.empty() && stack.peek() == BACKTICK) { + if (!stack.isEmpty() && stack.peek() == BACKTICK) { state = ParserState.IN_TEMPLATE; } break; @@ -238,7 +239,7 @@ private void inTemplateState(char character) { state = ParserState.IN_TEMPLATE_AFTER_DOLLAR; break; case BACKTICK: - if (!stack.empty() && stack.peek() == BACKTICK) { + if (!stack.isEmpty() && stack.peek() == BACKTICK) { state = ParserState.NORMAL; stack.pop(); break; @@ -310,6 +311,6 @@ public boolean isIncomplete() { return true; } // Otherwise, all brackets/backticks are closed is completion - return !stack.empty(); + return !stack.isEmpty(); } } diff --git a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/jline/validator/InputValidator.java b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/jline/validator/InputValidator.java index 035364f4761c..947a58440892 100644 --- a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/jline/validator/InputValidator.java +++ b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/jline/validator/InputValidator.java @@ -26,7 +26,7 @@ public class InputValidator { public boolean isComplete(String source) { - if (source.length() == 0 || source.startsWith("/")) { + if (source.isEmpty() || source.startsWith("/")) { return true; } else { Validator moduleMemberValidator = new ModuleMemberValidator(); diff --git a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/utils/FileUtils.java b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/utils/FileUtils.java index 79cad030a59d..e853db527f0a 100644 --- a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/utils/FileUtils.java +++ b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/utils/FileUtils.java @@ -34,9 +34,13 @@ * * @since 2.0.0 */ -public class FileUtils { +public final class FileUtils { + private static final String SPECIAL_DELIMITER = "\\A"; + private FileUtils() { + } + /** * Reads the file content from the resources. * diff --git a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/utils/IncompleteInputFinder.java b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/utils/IncompleteInputFinder.java index a4cde36035fa..066e3d13a3e9 100644 --- a/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/utils/IncompleteInputFinder.java +++ b/ballerina-shell/modules/shell-cli/src/main/java/io/ballerina/shell/cli/utils/IncompleteInputFinder.java @@ -197,7 +197,7 @@ public Boolean transform(BlockStatementNode node) { return true; } - if (node.statements().size() > 0) { + if (!node.statements().isEmpty()) { return node.statements().get(0).apply(this); } diff --git a/ballerina-shell/modules/shell-cli/src/test/java/io/ballerina/shell/cli/test/base/TestIntegrator.java b/ballerina-shell/modules/shell-cli/src/test/java/io/ballerina/shell/cli/test/base/TestIntegrator.java index f1821a8c10b9..0d9a4357b3e1 100644 --- a/ballerina-shell/modules/shell-cli/src/test/java/io/ballerina/shell/cli/test/base/TestIntegrator.java +++ b/ballerina-shell/modules/shell-cli/src/test/java/io/ballerina/shell/cli/test/base/TestIntegrator.java @@ -28,7 +28,6 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; -import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; @@ -62,8 +61,8 @@ public TestIntegrator(InputStream inputStream, OutputStream outputStream, ByteAr @Override public void run() { try { - PrintStream testPrint = new PrintStream(outputStream, true, Charset.defaultCharset()); - InputStreamReader inStreamReader = new InputStreamReader(inputStream, Charset.defaultCharset()); + PrintStream testPrint = new PrintStream(outputStream, true, StandardCharsets.UTF_8); + InputStreamReader inStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); BufferedReader testReader = new BufferedReader(inStreamReader); // The response here is not testable because it can change. @@ -96,7 +95,7 @@ public void run() { testCase.getDescription()); stdoutStream.reset(); } - } catch (IOException | InterruptedException ignored) { + } catch (IOException ignored) { } } @@ -116,10 +115,9 @@ private String readResponse(BufferedReader stream) throws IOException { /** * Send the data given to the specific stream. */ - private void sendRequest(PrintStream stream, String string) throws InterruptedException { - stream.append(string); - stream.println(System.lineSeparator()); - stream.flush(); + private void sendRequest(PrintStream stream, String string) { + // This is a workaround since with double `System.lineSeparator()` the tests fail on windows. + stream.append(string).append("\n\n").flush(); } /** diff --git a/ballerina-shell/modules/shell-cli/src/test/java/io/ballerina/shell/cli/test/integration/AbstractIntegrationTest.java b/ballerina-shell/modules/shell-cli/src/test/java/io/ballerina/shell/cli/test/integration/AbstractIntegrationTest.java index a9ba48fc3522..4cb43ad4bcf3 100644 --- a/ballerina-shell/modules/shell-cli/src/test/java/io/ballerina/shell/cli/test/integration/AbstractIntegrationTest.java +++ b/ballerina-shell/modules/shell-cli/src/test/java/io/ballerina/shell/cli/test/integration/AbstractIntegrationTest.java @@ -30,7 +30,7 @@ import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.io.PrintStream; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.List; /** @@ -54,7 +54,7 @@ protected void test(String fileName) throws Exception { PrintStream origOut = System.out; try { ByteArrayOutputStream stdOut = new ByteArrayOutputStream(); - PrintStream interceptedOutStream = new PrintStream(stdOut, true, Charset.defaultCharset()); + PrintStream interceptedOutStream = new PrintStream(stdOut, true, StandardCharsets.UTF_8); System.setOut(interceptedOutStream); TestIntegrator testIntegrator = new TestIntegrator(testIn, testOut, stdOut, testCases); diff --git a/ballerina-shell/modules/shell-cli/src/test/java/io/ballerina/shell/cli/test/validator/ValidatorTest.java b/ballerina-shell/modules/shell-cli/src/test/java/io/ballerina/shell/cli/test/validator/ValidatorTest.java index 05b052e13776..a845a4fee43b 100644 --- a/ballerina-shell/modules/shell-cli/src/test/java/io/ballerina/shell/cli/test/validator/ValidatorTest.java +++ b/ballerina-shell/modules/shell-cli/src/test/java/io/ballerina/shell/cli/test/validator/ValidatorTest.java @@ -57,9 +57,10 @@ public void testValidator() { Assert.assertFalse(inputValidator.isComplete("while (x < y)")); // For-each statements - Assert.assertTrue(inputValidator.isComplete("foreach var emp in top3 {\n" + - " io:println(emp);\n" + - "}")); + Assert.assertTrue(inputValidator.isComplete(""" + foreach var emp in top3 { + io:println(emp); + }""")); Assert.assertFalse(inputValidator.isComplete("foreach var emp in top3")); // TODO : fix #34989 @@ -68,51 +69,56 @@ public void testValidator() { // Function definitions Assert.assertTrue(inputValidator.isComplete("function foo() {\n" + "}")); - Assert.assertTrue(inputValidator.isComplete("\n" + - "\n" + - "function sum2(float[] v) returns float {\n" + - " float r = 0.0;\n" + - "\n" + - " foreach int i in 0 ..< v.length() {\n" + - " r += v[i];\n" + - " }\n" + - "\n" + - " return r;\n" + - "}")); - Assert.assertTrue(inputValidator.isComplete("function name() {\n" + - "}\n" + - "\n" + - "function foo() {\n" + - "}")); + Assert.assertTrue(inputValidator.isComplete(""" + + + function sum2(float[] v) returns float { + float r = 0.0; + + foreach int i in 0 ..< v.length() { + r += v[i]; + } + + return r; + }""")); + Assert.assertTrue(inputValidator.isComplete(""" + function name() { + } + + function foo() { + }""")); Assert.assertTrue(inputValidator.isComplete("var f = function () { x = 12; }")); Assert.assertFalse(inputValidator.isComplete("function parse(string s) returns int|error {")); Assert.assertFalse(inputValidator.isComplete("function parse(string s)")); // Type definitions - Assert.assertTrue(inputValidator.isComplete("type Coord record {\n" + - " int x;\n" + - " int y;\n" + - "};\n" + - "\n" + - "type Coord2 record {\n" + - " int a;\n" + - " int b;\n" + - "};")); + Assert.assertTrue(inputValidator.isComplete(""" + type Coord record { + int x; + int y; + }; + + type Coord2 record { + int a; + int b; + };""")); Assert.assertFalse(inputValidator.isComplete("type Coord record")); Assert.assertFalse(inputValidator.isComplete("type Coord record {\n" + "int x;")); // Query Expressions - Assert.assertTrue(inputValidator.isComplete("Employee[] employees = [\n" + - " {firstName: \"Jones\", lastName: \"Welsh\", salary: 1000.00},\n" + - " ];")); - Assert.assertTrue(inputValidator.isComplete("Employee[] top3 = from var e in employees\n" + - " order by e.salary descending\n" + - "\n" + - " limit 3\n" + - "\n" + - " select e;")); + Assert.assertTrue(inputValidator.isComplete(""" + Employee[] employees = [ + {firstName: "Jones", lastName: "Welsh", salary: 1000.00}, + ];""")); + Assert.assertTrue(inputValidator.isComplete(""" + Employee[] top3 = from var e in employees + order by e.salary descending + + limit 3 + + select e;""")); Assert.assertFalse(inputValidator.isComplete("from var e in employees\n" + " order by e.salary descending")); @@ -121,13 +127,13 @@ public void testValidator() { " {firstName: \"Jones\", lastName: \"Welsh\", salary: 1000.00},")); Assert.assertFalse(inputValidator.isComplete("Employee[] top3 = from var e in employees\n" + " order by e.salary descending")); - Assert.assertFalse(inputValidator.isComplete( - "Employee[] top3 = from var e in employees\n" + - " order by e.salary descending\n" + - "\n" + - " limit 3\n" + - "\n" + - " select")); + Assert.assertFalse(inputValidator.isComplete(""" + Employee[] top3 = from var e in employees + order by e.salary descending + + limit 3 + + select""")); Assert.assertFalse(inputValidator.isComplete("int[] evenNums = from var i in nums\n" + " where i % 2 == 0")); @@ -137,12 +143,13 @@ public void testValidator() { Assert.assertFalse(inputValidator.isComplete("public class Counter {")); // Expressions - Assert.assertTrue(inputValidator.isComplete("from var e in employees\n" + - " order by e.salary descending\n" + - "\n" + - " limit 3\n" + - "\n" + - " select e;")); + Assert.assertTrue(inputValidator.isComplete(""" + from var e in employees + order by e.salary descending + + limit 3 + + select e;""")); Assert.assertFalse(inputValidator.isComplete("x + ")); Assert.assertFalse(inputValidator.isComplete("from var i in nums\n" + @@ -157,88 +164,94 @@ public void testValidator() { Assert.assertFalse(inputValidator.isComplete("worker A {")); // Complete code examples - Assert.assertTrue(inputValidator.isComplete("import ballerina/io;\n" + - "\n" + - "public function foo() {\n" + - "\n" + - "}\n" + - "\n" + - "public function foo2() {\n" + - "\n" + - "}")); - Assert.assertTrue(inputValidator.isComplete("import ballerina/io;\n" + - "\n" + - "int x = 1;\n" + - "\n" + - "public function foo() {\n" + - "\n" + - "}\n" + - "\n" + - "public function name() {\n" + - "\n" + - "}")); - Assert.assertTrue(inputValidator.isComplete("function foo() {\n" + - "\n" + - " int x = 5;\n" + - "\n" + - " if (x < 10) {\n" + - " io:println(x);\n" + - " }\n" + - "\n" + - " while (x < 10) {\n" + - " x = x + 1;\n" + - " }\n" + - "\n" + - "}")); + Assert.assertTrue(inputValidator.isComplete(""" + import ballerina/io; - // Test case related to annotation not attached to construct error message - Assert.assertTrue(inputValidator.isComplete("@http:ServiceConfig {\n" + - " cors: {\n" + - " allowOrigins: [\"http://www.m3.com\", \"http://www.hello.com\"],\n" + - " allowCredentials: false,\n" + - " allowHeaders: [\"CORELATION_ID\"],\n" + - " exposeHeaders: [\"X-CUSTOM-HEADER\"],\n" + - " maxAge: 84900\n" + - " }\n" + - "}")); + public function foo() { - // Multiple function testcases - Assert.assertFalse(inputValidator.isComplete("function name() {\n" + - " int x = 1;\n" + - "}\n" + - "\n" + - "function name1() {\n" + - " name();")); - Assert.assertFalse(inputValidator.isComplete("function name() {\n" + - " int x = 1\n" + - "}\n" + - "\n" + - "function name1() {\n" + - " name();")); - - Assert.assertTrue(inputValidator.isComplete("function name() {\n" + - " int x = 1;\n" + - "}\n" + - "\n" + - "function name1() {\n" + - " name();" + - "}")); + } - Assert.assertTrue(inputValidator.isComplete("function name() {\n" + - " int x = 1\n" + - "}\n" + - "\n" + - "function name1() {\n" + - " name();" + - "}")); + public function foo2() { - Assert.assertTrue(inputValidator.isComplete("function name() {\n" + - " int x = 1\n" + - "}\n" + - "\n" + - "function name1() {\n" + - " name();" + - "}")); + }""")); + Assert.assertTrue(inputValidator.isComplete(""" + import ballerina/io; + + int x = 1; + + public function foo() { + + } + + public function name() { + + }""")); + Assert.assertTrue(inputValidator.isComplete(""" + function foo() { + + int x = 5; + + if (x < 10) { + io:println(x); + } + + while (x < 10) { + x = x + 1; + } + + }""")); + + // Test case related to annotation not attached to construct error message + Assert.assertTrue(inputValidator.isComplete(""" + @http:ServiceConfig { + cors: { + allowOrigins: ["http://www.m3.com", "http://www.hello.com"], + allowCredentials: false, + allowHeaders: ["CORELATION_ID"], + exposeHeaders: ["X-CUSTOM-HEADER"], + maxAge: 84900 + } + }""")); + + // Multiple function testcases + Assert.assertFalse(inputValidator.isComplete(""" + function name() { + int x = 1; + } + + function name1() { + name();""")); + Assert.assertFalse(inputValidator.isComplete(""" + function name() { + int x = 1 + } + + function name1() { + name();""")); + + Assert.assertTrue(inputValidator.isComplete(""" + function name() { + int x = 1; + } + + function name1() { + name();}""")); + + Assert.assertTrue(inputValidator.isComplete(""" + function name() { + int x = 1 + } + + function name1() { + name();}""")); + + Assert.assertTrue(inputValidator.isComplete(""" + function name() { + int x = 1 + } + + function name1() { + name();}""")); // Command related testcases Assert.assertTrue(inputValidator.isComplete(" ")); diff --git a/ballerina-shell/modules/shell-core/build.gradle b/ballerina-shell/modules/shell-core/build.gradle index 4586151ca6f2..050f450c7b58 100644 --- a/ballerina-shell/modules/shell-core/build.gradle +++ b/ballerina-shell/modules/shell-core/build.gradle @@ -16,8 +16,10 @@ * under the License. */ -apply from: "$rootDir/gradle/javaProject.gradle" -apply from: "$rootDir/gradle/ballerinaLangLibLoad.gradle" +plugins { + id 'javaProject' + id 'ballerinaLangLibLoad' +} description = 'Ballerina - Ballerina Shell' @@ -30,10 +32,10 @@ dependencies { implementation project(':ballerina-tools-api') implementation project(':ballerina-runtime') implementation project(':identifier-util') - implementation 'com.github.spullara.mustache.java:compiler' + implementation libs.mustache.java.compiler - testImplementation('org.testng:testng') - testImplementation('com.google.code.gson:gson') + testImplementation libs.testng + testImplementation libs.gson } test { @@ -44,9 +46,14 @@ test { compileJava { doFirst { - options.compilerArgs = [ - '--module-path', classpath.asPath, - ] + options.compilerArgs << '--module-path' << classpath.asPath + classpath = files() + } +} + +javadoc { + doFirst { + options.modulePath = classpath.toList() classpath = files() } } diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/EvaluatorImpl.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/EvaluatorImpl.java index 97763f957944..ec9673a2aa13 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/EvaluatorImpl.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/EvaluatorImpl.java @@ -36,7 +36,7 @@ import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; -import java.nio.file.Paths; +import java.nio.file.Path; import java.util.Collection; import java.util.HashSet; import java.util.Optional; @@ -80,6 +80,7 @@ public String evaluate(String source) throws BallerinaShellException { } } + @Override public ShellCompilation getCompilation(String source) { PackageCompilation compilation; ExceptionStatus exceptionStatus; @@ -165,7 +166,7 @@ public String getBufferFileUri() throws IOException { @Override public void evaluateDeclarationFile(String filePath) throws BallerinaShellException { try { - String statements = Files.readString(Paths.get(filePath), Charset.defaultCharset()); + String statements = Files.readString(Path.of(filePath), Charset.defaultCharset()); Collection nodes = treeParser.parseDeclarations(statements); Collection snippets = snippetFactory.createSnippets(nodes); getValue(Optional.ofNullable(invoker.getCompilation(snippets))); diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/NotebookReturnValue.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/NotebookReturnValue.java index e9e35bb3bcc4..03ba6e276e0e 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/NotebookReturnValue.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/NotebookReturnValue.java @@ -20,7 +20,7 @@ /** * Return value after invoking snippet. - * Contains result as an object & exception status related to compilation + * Contains result as an object & exception status related to compilation * * @since 2201.1.1 */ diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/ShellCompilation.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/ShellCompilation.java index d49b4bec4ded..bf50155e0999 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/ShellCompilation.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/ShellCompilation.java @@ -24,7 +24,7 @@ /** * Shell Compilation class. - * Contains package compilation & exception status related to compilation + * Contains package compilation & exception status related to compilation * * @since 2.0.0 */ diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/ShellReturnValue.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/ShellReturnValue.java index d7607f953fd2..e79530cf3551 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/ShellReturnValue.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/ShellReturnValue.java @@ -20,7 +20,7 @@ /** * Shell Compilation class. - * Contains package compilation & exception status related to compilation + * Contains package compilation & exception status related to compilation * * @since 2.0.0 */ diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/invoker/ShellSnippetsInvoker.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/invoker/ShellSnippetsInvoker.java index b9dbd3fc7a02..19543b828c74 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/invoker/ShellSnippetsInvoker.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/invoker/ShellSnippetsInvoker.java @@ -43,6 +43,7 @@ import io.ballerina.shell.invoker.classload.context.ClassLoadContext; import io.ballerina.shell.snippet.Snippet; import io.ballerina.shell.utils.StringUtils; +import io.ballerina.tools.diagnostics.Diagnostic; import io.ballerina.tools.diagnostics.DiagnosticSeverity; import java.io.File; @@ -56,11 +57,12 @@ import java.nio.file.Path; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Function; -import java.util.stream.Collectors; /** * Invoker that invokes a command to evaluate a list of snippets. @@ -276,7 +278,7 @@ protected PackageCompilation compile(Project project) throws InvokerException { PackageCompilation packageCompilation = project.currentPackage().getCompilation(); DiagnosticResult diagnosticResult = packageCompilation.diagnosticResult(); - for (io.ballerina.tools.diagnostics.Diagnostic diagnostic : diagnosticResult.diagnostics()) { + for (Diagnostic diagnostic : diagnosticResult.diagnostics()) { DiagnosticSeverity severity = diagnostic.diagnosticInfo().severity(); if (severity == DiagnosticSeverity.ERROR) { containErrors = true; @@ -328,7 +330,7 @@ protected void compileImportStatement(String importStatement) throws InvokerExce * @return Whether the compilation contains MODULE_NOT_FOUND error. */ private boolean containsModuleNotFoundError(PackageCompilation compilation) { - for (io.ballerina.tools.diagnostics.Diagnostic diagnostic : compilation.diagnosticResult().diagnostics()) { + for (Diagnostic diagnostic : compilation.diagnosticResult().diagnostics()) { if (diagnostic.diagnosticInfo().code().equals(MODULE_NOT_FOUND_CODE)) { return true; } @@ -376,8 +378,8 @@ protected void executeProject(JBallerinaBackend jBallerinaBackend) throws Invoke // First run configure initialization // TODO: (#28662) After configurables can be supported, change this to that file location invokeMethodDirectly(classLoader, CONFIGURE_INIT_CLASS_NAME, CONFIGURE_INIT_METHOD_NAME, - new Class[]{String[].class, Path[].class, String.class}, new Object[]{new String[]{}, - new Path[]{}, null}); + new Class[]{Map.class, String[].class, Path[].class, String.class}, + new Object[]{new HashMap<>(), new String[]{}, new Path[]{}, null}); // Initialize the module invokeScheduledMethod(classLoader, MODULE_INIT_CLASS_NAME, MODULE_INIT_METHOD_NAME); // Start the module @@ -391,8 +393,8 @@ protected void executeProject(JBallerinaBackend jBallerinaBackend) throws Invoke List stacktrace = Arrays.stream(panicError.getCause().getStackTrace()) .filter(element -> !(element.toString().contains(MODULE_STATEMENT_METHOD_NAME) || element.toString().contains(MODULE_RUN_METHOD_NAME))) - .collect(Collectors.toList()) - .stream().map(element -> "at " + element.getMethodName() + "()").collect(Collectors.toList()); + .toList() + .stream().map(element -> "at " + element.getMethodName() + "()").toList(); errorStream.println("panic: " + StringUtils.getErrorStringValue(panicError.getCause())); stacktrace.forEach(errorStream::println); addErrorDiagnostic("Execution aborted due to unhandled runtime error."); @@ -434,9 +436,9 @@ protected Object invokeScheduledMethod(ClassLoader classLoader, String className // Unexpected runtime error throw new InvokerPanicException(panic); } - if (result instanceof Throwable) { + if (result instanceof Throwable throwable) { // Function returned error (panic) - throw new InvokerPanicException((Throwable) result); + throw new InvokerPanicException(throwable); } return result; } catch (ClassNotFoundException e) { @@ -511,7 +513,7 @@ private Function createInvokerCallback(Method method) { * @param diagnostic Diagnostic to show. * @return The string with position highlighted. */ - private String highlightedDiagnostic(Module module, io.ballerina.tools.diagnostics.Diagnostic diagnostic) { + private String highlightedDiagnostic(Module module, Diagnostic diagnostic) { Optional documentId = module.documentIds().stream().findFirst(); Document document = module.document(documentId.orElseThrow()); return StringUtils.highlightDiagnostic(document.textDocument(), diagnostic); diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/invoker/classload/ClassLoadInvoker.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/invoker/classload/ClassLoadInvoker.java index 2b8ec677b7dc..4617ea0bf74d 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/invoker/classload/ClassLoadInvoker.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/invoker/classload/ClassLoadInvoker.java @@ -227,16 +227,14 @@ public PackageCompilation getCompilation(Collection newSnippets) throws // Others are processed later. for (Snippet newSnippet : newSnippets) { - if (newSnippet instanceof ImportDeclarationSnippet) { - processImport((ImportDeclarationSnippet) newSnippet); + if (newSnippet instanceof ImportDeclarationSnippet importSnippet) { + processImport(importSnippet); - } else if (newSnippet instanceof VariableDeclarationSnippet) { - VariableDeclarationSnippet varDclnSnippet = (VariableDeclarationSnippet) newSnippet; + } else if (newSnippet instanceof VariableDeclarationSnippet varDclnSnippet) { variableNames.addAll(varDclnSnippet.names()); variableDeclarations.put(varDclnSnippet, varDclnSnippet.names()); - } else if (newSnippet instanceof ModuleMemberDeclarationSnippet) { - ModuleMemberDeclarationSnippet moduleDclnSnippet = (ModuleMemberDeclarationSnippet) newSnippet; + } else if (newSnippet instanceof ModuleMemberDeclarationSnippet moduleDclnSnippet) { Identifier moduleDeclarationName = moduleDclnSnippet.name(); moduleDeclarations.put(moduleDeclarationName, moduleDclnSnippet); availableModuleDeclarations.put(moduleDeclarationName, moduleDclnSnippet); @@ -244,8 +242,8 @@ public PackageCompilation getCompilation(Collection newSnippets) throws .map(Identifier::new).collect(Collectors.toSet()); newImports.put(moduleDeclarationName, usedPrefixes); - } else if (newSnippet instanceof ExecutableSnippet) { - executableSnippets.add((ExecutableSnippet) newSnippet); + } else if (newSnippet instanceof ExecutableSnippet executableSnippet) { + executableSnippets.add(executableSnippet); } else { throw new UnsupportedOperationException("Unimplemented snippet category."); @@ -560,7 +558,7 @@ private Collection globalVariableSymbols(Project project, return compilation.getSemanticModel(moduleId).moduleSymbols().stream() .filter(s -> s instanceof VariableSymbol || s instanceof FunctionSymbol) .map(GlobalVariableSymbol::fromSymbol) - .collect(Collectors.toList()); + .toList(); } /** @@ -650,17 +648,17 @@ public List availableVariables() { } } - if (variablesDeclarations.size() > 0) { + if (!variablesDeclarations.isEmpty()) { varStrings.add("Variable declarations"); varStrings.addAll(variablesDeclarations); } - if (finalVariablesDeclarations.size() > 0) { + if (!finalVariablesDeclarations.isEmpty()) { varStrings.add("Final variable declarations"); varStrings.addAll(finalVariablesDeclarations); } - if (constDeclarations.size() > 0) { + if (!constDeclarations.isEmpty()) { varStrings.add("Constant declarations"); varStrings.addAll(constDeclarations); } diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/invoker/classload/GlobalVariableSymbol.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/invoker/classload/GlobalVariableSymbol.java index 6bd1b5d1f5af..74879ee30a78 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/invoker/classload/GlobalVariableSymbol.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/invoker/classload/GlobalVariableSymbol.java @@ -42,10 +42,10 @@ public static GlobalVariableSymbol fromSymbol(Symbol symbol) { if (symbol.getName().isEmpty()) { throw new UnsupportedOperationException("Cannot create a global symbol without name"); } - if (symbol instanceof VariableSymbol) { - return new GlobalVariableSymbol(symbol.getName().get(), ((VariableSymbol) symbol).typeDescriptor()); - } else if (symbol instanceof FunctionSymbol) { - return new GlobalVariableSymbol(symbol.getName().get(), ((FunctionSymbol) symbol).typeDescriptor()); + if (symbol instanceof VariableSymbol variableSymbol) { + return new GlobalVariableSymbol(symbol.getName().get(), variableSymbol.typeDescriptor()); + } else if (symbol instanceof FunctionSymbol functionSymbol) { + return new GlobalVariableSymbol(symbol.getName().get(), functionSymbol.typeDescriptor()); } throw new UnsupportedOperationException("Symbol type not supported for creating global variable."); } diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/invoker/classload/ImportsManager.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/invoker/classload/ImportsManager.java index 9f2dad2a39a8..829c6d9c635a 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/invoker/classload/ImportsManager.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/invoker/classload/ImportsManager.java @@ -42,7 +42,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; /** * Imports that were stored to be able to search with the prefix. @@ -288,7 +287,7 @@ protected String extractImportsFromType(TypeSymbol typeSymbol, Set i if (nextStart != 0) { newText.append(text.substring(nextStart)); } - return newText.length() > 0 ? newText.toString() : text; + return !newText.isEmpty() ? newText.toString() : text; } /** @@ -364,7 +363,7 @@ private static List getBallerinaKeywords() { } }) .filter(Objects::nonNull) - .collect(Collectors.toList()); + .toList(); } catch (ClassNotFoundException e) { return Collections.emptyList(); } diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/ParserConstants.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/ParserConstants.java index a56297d31a91..bf03bbc1b2fd 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/ParserConstants.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/ParserConstants.java @@ -25,7 +25,7 @@ * * @since 2.0.0 */ -public class ParserConstants { +public final class ParserConstants { public static final String WRAPPER_PREFIX = "__shell_wrapper__"; diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/SerialTreeParser.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/SerialTreeParser.java index ce933d37e90a..9aed29690285 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/SerialTreeParser.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/SerialTreeParser.java @@ -120,8 +120,8 @@ public Collection parseDeclarations(String source) throws TreeParserExcept * Whether the declaration is allowed to be parsed. */ private boolean isModuleDeclarationAllowed(ModuleMemberDeclarationNode declarationNode) { - if (declarationNode instanceof FunctionDefinitionNode) { - String functionName = ((FunctionDefinitionNode) declarationNode).functionName().text(); + if (declarationNode instanceof FunctionDefinitionNode functionDefinitionNode) { + String functionName = functionDefinitionNode.functionName().text(); if (ParserConstants.isFunctionNameRestricted(functionName)) { addWarnDiagnostic("Found '" + functionName + "' function in the declarations.\n" + "Discarded '" + functionName + "' function without loading."); diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/trials/DualTreeParserTrial.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/trials/DualTreeParserTrial.java index 1d82eac06212..09e2a0ddf565 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/trials/DualTreeParserTrial.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/trials/DualTreeParserTrial.java @@ -36,16 +36,9 @@ public DualTreeParserTrial(TrialTreeParser parentParser) { } @Override - public Collection parse(String source) throws ParserTrialFailedException { - try { - return parseSource(source); - } catch (ParserTrialFailedException e) { - if (source.endsWith(SEMICOLON)) { - return parseSource(source.substring(0, source.length() - 1)); - } - throw e; - } + public Collection parse(String source) { + return parseSource(source); } - public abstract Collection parseSource(String source) throws ParserTrialFailedException; + public abstract Collection parseSource(String source); } diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/trials/ExpressionTrial.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/trials/ExpressionTrial.java index 4f19a15fa9e9..2461be5382f7 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/trials/ExpressionTrial.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/trials/ExpressionTrial.java @@ -22,6 +22,7 @@ import io.ballerina.compiler.syntax.tree.ExpressionNode; import io.ballerina.compiler.syntax.tree.Node; import io.ballerina.compiler.syntax.tree.NodeParser; +import io.ballerina.shell.parser.ParserConstants; import io.ballerina.shell.parser.TrialTreeParser; import java.util.ArrayList; @@ -57,7 +58,16 @@ public Collection parse(String source) throws ParserTrialFailedException { if (expressionNode.hasDiagnostics()) { throw new ParserTrialFailedException("Error occurred during extracting expression from the statement"); } + validateExpression(expressionNode.toSourceCode()); nodes.add(expressionNode); return nodes; } + + private void validateExpression(String expression) { + String functionName = expression.replaceAll("\\s*\\(.*", ""); + if (ParserConstants.isFunctionNameRestricted(functionName)) { + String message = String.format("Function name '%s' not allowed in Ballerina Shell.%n", functionName); + throw new InvalidMethodException(message); + } + } } diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/trials/ModuleMemberTrial.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/trials/ModuleMemberTrial.java index 6ce131e0bbe1..15f978e41e0c 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/trials/ModuleMemberTrial.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/parser/trials/ModuleMemberTrial.java @@ -62,12 +62,12 @@ public Collection parse(String source) throws ParserTrialFailedException { ModulePartNode node = tree.rootNode(); NodeList members = node.members(); Iterator importIterator = node.imports().iterator(); - Iterator memberIterator = members.iterator(); + Iterator memberIterator = members.iterator(); while (importIterator.hasNext()) { nodes.add(importIterator.next()); } while (memberIterator.hasNext()) { - ModuleMemberDeclarationNode dclnNode = (ModuleMemberDeclarationNode) memberIterator.next(); + ModuleMemberDeclarationNode dclnNode = memberIterator.next(); validateModuleDeclaration(dclnNode); nodes.add(dclnNode); } @@ -75,8 +75,8 @@ public Collection parse(String source) throws ParserTrialFailedException { } private void validateModuleDeclaration(ModuleMemberDeclarationNode declarationNode) { - if (declarationNode instanceof FunctionDefinitionNode) { - String functionName = ((FunctionDefinitionNode) declarationNode).functionName().text(); + if (declarationNode instanceof FunctionDefinitionNode functionDefinitionNode) { + String functionName = functionDefinitionNode.functionName().text(); if (ParserConstants.isFunctionNameRestricted(functionName)) { String message = "Function name " + "'" + functionName + "'" + " not allowed in Ballerina Shell.\n"; throw new InvalidMethodException(message); diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/preprocessor/SeparatorPreprocessor.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/preprocessor/SeparatorPreprocessor.java index f7558b071090..4532bf022efb 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/preprocessor/SeparatorPreprocessor.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/preprocessor/SeparatorPreprocessor.java @@ -20,10 +20,11 @@ import io.ballerina.shell.exceptions.PreprocessorException; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; +import java.util.Deque; import java.util.List; -import java.util.Stack; /** * Preprocessor to split the input into several statements @@ -51,7 +52,7 @@ public Collection process(String input) throws PreprocessorException { List snippets = new ArrayList<>(); StringBuilder builder = new StringBuilder(); - Stack brackets = new Stack<>(); + Deque brackets = new ArrayDeque<>(); boolean isInBacktickLiteral = false; boolean isInQuoteLiteral = false; @@ -95,7 +96,7 @@ public Collection process(String input) throws PreprocessorException { } // Append remaining string to the statements. - if (builder.length() > 0) { + if (!builder.isEmpty()) { addToList(snippets, builder); } diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/factory/BasicSnippetFactory.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/factory/BasicSnippetFactory.java index 371d7b7b51e8..15377f6db441 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/factory/BasicSnippetFactory.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/factory/BasicSnippetFactory.java @@ -126,8 +126,7 @@ public class BasicSnippetFactory extends SnippetFactory { @Override public ImportDeclarationSnippet createImportSnippet(Node node) { - if (node instanceof ImportDeclarationNode) { - ImportDeclarationNode importDeclarationNode = (ImportDeclarationNode) node; + if (node instanceof ImportDeclarationNode importDeclarationNode) { return new ImportDeclarationSnippet(importDeclarationNode); } return null; @@ -143,10 +142,9 @@ public List createVariableDeclarationSnippets(Node n return null; } - if (node instanceof ModuleVariableDeclarationNode) { - dclnNode = (ModuleVariableDeclarationNode) node; - } else if (node instanceof VariableDeclarationNode) { - VariableDeclarationNode varNode = (VariableDeclarationNode) node; + if (node instanceof ModuleVariableDeclarationNode moduleVariableDeclarationNode) { + dclnNode = moduleVariableDeclarationNode; + } else if (node instanceof VariableDeclarationNode varNode) { VariableDeclarationNode newNode = null; NodeList qualifiers = NodeFactory.createEmptyNodeList(); // Only final qualifier is transferred. @@ -230,14 +228,14 @@ public ModuleMemberDeclarationSnippet createModuleMemberDeclarationSnippet(Node return null; } - if (node instanceof ModuleMemberDeclarationNode) { + if (node instanceof ModuleMemberDeclarationNode moduleMemberDeclarationNode) { assert MODULE_MEM_DCLNS.containsKey(node.getClass()); SnippetSubKind subKind = MODULE_MEM_DCLNS.get(node.getClass()); if (subKind.hasError()) { addErrorDiagnostic(subKind.getError()); throw new SnippetException(); } else if (subKind.isValid()) { - return new ModuleMemberDeclarationSnippet(subKind, (ModuleMemberDeclarationNode) node); + return new ModuleMemberDeclarationSnippet(subKind, moduleMemberDeclarationNode); } } return null; @@ -264,8 +262,8 @@ public StatementSnippet createStatementSnippet(Node node) throws SnippetExceptio @Override public ExpressionSnippet createExpressionSnippet(Node node) { - if (node instanceof ExpressionNode) { - return new ExpressionSnippet((ExpressionNode) node); + if (node instanceof ExpressionNode expressionNode) { + return new ExpressionSnippet(expressionNode); } return null; } @@ -277,11 +275,11 @@ public ExpressionSnippet createExpressionSnippet(Node node) { * @return node contains isolated keyword or not. */ private boolean containsIsolated(Node node) { - if (node instanceof ModuleVariableDeclarationNode) { - NodeList nodeList = ((ModuleVariableDeclarationNode) node).qualifiers(); + if (node instanceof ModuleVariableDeclarationNode moduleVariableDeclarationNode) { + NodeList nodeList = moduleVariableDeclarationNode.qualifiers(); return nodeList.stream().anyMatch(token -> token.kind() == SyntaxKind.ISOLATED_KEYWORD); - } else if (node instanceof FunctionDefinitionNode) { - NodeList nodeList = ((FunctionDefinitionNode) node).qualifierList(); + } else if (node instanceof FunctionDefinitionNode functionDefinitionNode) { + NodeList nodeList = functionDefinitionNode.qualifierList(); return nodeList.stream().anyMatch(token -> token.kind() == SyntaxKind.ISOLATED_KEYWORD); } @@ -289,23 +287,21 @@ private boolean containsIsolated(Node node) { } private boolean isSupportedAction(SyntaxKind nodeKind) { - switch (nodeKind) { - case REMOTE_METHOD_CALL_ACTION: - case BRACED_ACTION: - case CHECK_ACTION: - case START_ACTION: - case TRAP_ACTION: - case FLUSH_ACTION: - case ASYNC_SEND_ACTION: - case SYNC_SEND_ACTION: - case RECEIVE_ACTION: - case WAIT_ACTION: - case QUERY_ACTION: - case COMMIT_ACTION: - case CLIENT_RESOURCE_ACCESS_ACTION: - return true; - default: - return false; - } + return switch (nodeKind) { + case REMOTE_METHOD_CALL_ACTION, + BRACED_ACTION, + CHECK_ACTION, + START_ACTION, + TRAP_ACTION, + FLUSH_ACTION, + ASYNC_SEND_ACTION, + SYNC_SEND_ACTION, + RECEIVE_ACTION, + WAIT_ACTION, + QUERY_ACTION, + COMMIT_ACTION, + CLIENT_RESOURCE_ACCESS_ACTION -> true; + default -> false; + }; } } diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/factory/SnippetFactory.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/factory/SnippetFactory.java index dfa89f042784..ddf79ac55e5b 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/factory/SnippetFactory.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/factory/SnippetFactory.java @@ -146,7 +146,7 @@ public abstract ModuleMemberDeclarationSnippet createModuleMemberDeclarationSnip * @param node Root node to create snippet from. * @return Snippet that contains the node. */ - public abstract Snippet createExpressionSnippet(Node node) throws SnippetException; + public abstract Snippet createExpressionSnippet(Node node); /** * Snippet creation helper interface. diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/types/AbstractSnippet.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/types/AbstractSnippet.java index 2f21c57fb11a..6ffbea9880d3 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/types/AbstractSnippet.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/types/AbstractSnippet.java @@ -30,7 +30,7 @@ import java.util.Set; /** - * An abstract implementation of {@link io.ballerina.shell.snippet.Snippet}. + * An abstract implementation of {@link Snippet}. * * @param Type of the child root node * @since 2.0.0 diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/types/ImportDeclarationSnippet.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/types/ImportDeclarationSnippet.java index 988669c1784c..ec58593d5d2a 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/types/ImportDeclarationSnippet.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/types/ImportDeclarationSnippet.java @@ -25,7 +25,6 @@ import io.ballerina.shell.utils.QuotedImport; import java.util.List; -import java.util.stream.Collectors; /** * Snippet that represent a import statement. @@ -59,7 +58,7 @@ public Identifier getPrefix() { */ public QuotedImport getImportedModule() { List moduleNames = rootNode.moduleName().stream().map(IdentifierToken::text) - .collect(Collectors.toList()); + .toList(); if (rootNode.orgName().isPresent()) { String orgName = rootNode.orgName().get().orgName().text(); return new QuotedImport(orgName, moduleNames); diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/types/ModuleMemberDeclarationSnippet.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/types/ModuleMemberDeclarationSnippet.java index 1e1eecff29b5..24f4e1aeb790 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/types/ModuleMemberDeclarationSnippet.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/snippet/types/ModuleMemberDeclarationSnippet.java @@ -51,27 +51,26 @@ public ModuleMemberDeclarationSnippet(SnippetSubKind subKind, ModuleMemberDeclar * If the module declaration has no name, this will return null. */ public Identifier name() { - if (rootNode instanceof ClassDefinitionNode) { - String className = ((ClassDefinitionNode) rootNode).className().text(); + if (rootNode instanceof ClassDefinitionNode classDefinitionNode) { + String className = classDefinitionNode.className().text(); return new Identifier(className); - } else if (rootNode instanceof ConstantDeclarationNode) { - String constName = ((ConstantDeclarationNode) rootNode).variableName().text(); + } else if (rootNode instanceof ConstantDeclarationNode constantDeclarationNode) { + String constName = constantDeclarationNode.variableName().text(); return new Identifier(constName); - } else if (rootNode instanceof EnumDeclarationNode) { - String enumName = ((EnumDeclarationNode) rootNode).identifier().text(); + } else if (rootNode instanceof EnumDeclarationNode enumDeclarationNode) { + String enumName = enumDeclarationNode.identifier().text(); return new Identifier(enumName); - } else if (rootNode instanceof FunctionDefinitionNode) { - String funcName = ((FunctionDefinitionNode) rootNode).functionName().text(); + } else if (rootNode instanceof FunctionDefinitionNode functionDefinitionNode) { + String funcName = functionDefinitionNode.functionName().text(); return new Identifier(funcName); - } else if (rootNode instanceof ListenerDeclarationNode) { - String listenerName = ((ListenerDeclarationNode) rootNode).variableName().text(); + } else if (rootNode instanceof ListenerDeclarationNode listenerDeclarationNode) { + String listenerName = listenerDeclarationNode.variableName().text(); return new Identifier(listenerName); - } else if (rootNode instanceof ModuleXMLNamespaceDeclarationNode) { - ModuleXMLNamespaceDeclarationNode namespaceNode = (ModuleXMLNamespaceDeclarationNode) rootNode; + } else if (rootNode instanceof ModuleXMLNamespaceDeclarationNode namespaceNode) { return namespaceNode.namespacePrefix().map(Token::text).map(Identifier::new) .orElseGet(this::createAnonModuleName); - } else if (rootNode instanceof TypeDefinitionNode) { - String typeName = ((TypeDefinitionNode) rootNode).typeName().text(); + } else if (rootNode instanceof TypeDefinitionNode typeDefinitionNode) { + String typeName = typeDefinitionNode.typeName().text(); return new Identifier(typeName); } else { return createAnonModuleName(); diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/utils/ModuleImporter.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/utils/ModuleImporter.java index 7c95fdd39cce..e7184dc9e272 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/utils/ModuleImporter.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/utils/ModuleImporter.java @@ -39,7 +39,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; /** * Support class to add required import statements. @@ -113,7 +112,7 @@ public List undefinedModules(Collection diagnostics) { } } - return moduleErrors.stream().distinct().collect(Collectors.toList()); + return moduleErrors.stream().distinct().toList(); } /** diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/utils/QuotedImport.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/utils/QuotedImport.java index 17a0585ba711..e4aeb69475bd 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/utils/QuotedImport.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/utils/QuotedImport.java @@ -21,7 +21,6 @@ import java.util.List; import java.util.Objects; import java.util.StringJoiner; -import java.util.stream.Collectors; /** * An import that has quoted orgname and module names. @@ -36,7 +35,7 @@ public QuotedImport(String orgName, List moduleNames) { this.orgName = orgName; this.moduleNames = moduleNames.stream() .map(Identifier::new) - .collect(Collectors.toList()); + .toList(); } public QuotedImport(List moduleNames) { diff --git a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/utils/StringUtils.java b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/utils/StringUtils.java index 00bf4493a5c2..5cc82527c6a6 100644 --- a/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/utils/StringUtils.java +++ b/ballerina-shell/modules/shell-core/src/main/java/io/ballerina/shell/utils/StringUtils.java @@ -20,6 +20,7 @@ import io.ballerina.identifier.Utils; import io.ballerina.runtime.api.values.BError; +import io.ballerina.tools.diagnostics.Diagnostic; import io.ballerina.tools.text.LinePosition; import io.ballerina.tools.text.LineRange; import io.ballerina.tools.text.TextDocument; @@ -34,13 +35,17 @@ * * @since 2.0.0 */ -public class StringUtils { +public final class StringUtils { + private static final int MAX_VAR_STRING_LENGTH = 78; private static final String QUOTE = "'"; private static final String SPACE = " "; private static final String CARET = "^"; private static final String DASH = "-"; + private StringUtils() { + } + /** * Creates an quoted identifier to use for variable names. * @@ -62,7 +67,7 @@ public static String quoted(String identifier) { */ public static String shortenedString(Object input) { String value = String.valueOf(input); - value = value.replaceAll("\n", ""); + value = value.replace("\n", ""); if (value.length() > MAX_VAR_STRING_LENGTH) { int subStrLength = MAX_VAR_STRING_LENGTH / 2; return value.substring(0, subStrLength) @@ -85,8 +90,7 @@ public static String shortenedString(Object input) { * @param diagnostic Diagnostic to show. * @return The string with position highlighted. */ - public static String highlightDiagnostic(TextDocument textDocument, - io.ballerina.tools.diagnostics.Diagnostic diagnostic) { + public static String highlightDiagnostic(TextDocument textDocument, Diagnostic diagnostic) { LineRange lineRange = diagnostic.location().lineRange(); LinePosition startLine = lineRange.startLine(); LinePosition endLine = lineRange.endLine(); @@ -159,8 +163,8 @@ public static String getExpressionStringValue(Object object) { * @return Converted string. */ public static String getErrorStringValue(Throwable error) { - if (error instanceof BError) { - return ((BError) error).getErrorMessage() + " " + ((BError) error).getDetails(); + if (error instanceof BError bError) { + return bError.getErrorMessage() + " " + bError.getDetails(); } return error.getMessage(); } @@ -172,7 +176,7 @@ public static String getErrorStringValue(Throwable error) { * @return Reformatted unicode string. */ public static String convertUnicode(char character) { - return "\\u{" + Integer.toHexString((int) character) + "}"; + return "\\u{" + Integer.toHexString(character) + "}"; } /** diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/AbstractEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/AbstractEvaluatorTest.java index 895d17cd73e8..e4a522dc221e 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/AbstractEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/AbstractEvaluatorTest.java @@ -49,7 +49,7 @@ public abstract class AbstractEvaluatorTest { * * @param fileName File containing test cases. */ - protected void testEvaluate(String fileName) throws BallerinaShellException { + protected void testEvaluate(String fileName) { // Create evaluator TestInvoker invoker = new TestInvoker(); Evaluator evaluator = new EvaluatorBuilder() diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/ActionEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/ActionEvaluatorTest.java index 1bbc48cb470c..8667e7d5d85c 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/ActionEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/ActionEvaluatorTest.java @@ -16,7 +16,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -31,22 +30,22 @@ public class ActionEvaluatorTest extends AbstractEvaluatorTest { private static final String VAR_EVALUATOR_TESTCASE = "testcases/evaluator/actions.var.json"; @Test - public void testEvaluateStart() throws BallerinaShellException { + public void testEvaluateStart() { testEvaluate(START_EVALUATOR_TESTCASE); } @Test - public void testEvaluateRemote() throws BallerinaShellException { + public void testEvaluateRemote() { testEvaluate(REMOTE_EVALUATOR_TESTCASE); } @Test - public void testEvaluateResource() throws BallerinaShellException { + public void testEvaluateResource() { testEvaluate(RESOURCE_EVALUATOR_TESTCASE); } @Test - public void testEvaluateVar() throws BallerinaShellException { + public void testEvaluateVar() { testEvaluate(VAR_EVALUATOR_TESTCASE); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/BasicTypeEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/BasicTypeEvaluatorTest.java index 2138884c6fde..e86a241a3bcb 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/BasicTypeEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/BasicTypeEvaluatorTest.java @@ -18,7 +18,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -34,27 +33,27 @@ public class BasicTypeEvaluatorTest extends AbstractEvaluatorTest { private static final String MAPS_EVALUATOR_TESTCASE = "testcases/evaluator/values.maps.json"; @Test - public void testEvaluateString() throws BallerinaShellException { + public void testEvaluateString() { testEvaluate(STRING_EVALUATOR_TESTCASE); } @Test - public void testEvaluateTuples() throws BallerinaShellException { + public void testEvaluateTuples() { testEvaluate(TUPLES_EVALUATOR_TESTCASE); } @Test - public void testEvaluateArrays() throws BallerinaShellException { + public void testEvaluateArrays() { testEvaluate(ARRAYS_EVALUATOR_TESTCASE); } @Test - public void testEvaluateTable() throws BallerinaShellException { + public void testEvaluateTable() { testEvaluate(TABLE_EVALUATOR_TESTCASE); } @Test - public void testEvaluateMaps() throws BallerinaShellException { + public void testEvaluateMaps() { testEvaluate(MAPS_EVALUATOR_TESTCASE); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/BasicsEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/BasicsEvaluatorTest.java index eb53b66d6652..faf6f3064586 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/BasicsEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/BasicsEvaluatorTest.java @@ -18,7 +18,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -38,48 +37,48 @@ public class BasicsEvaluatorTest extends AbstractEvaluatorTest { private static final String BASICS_ERRORS_TESTCASE = "testcases/evaluator/basics.errors.json"; @Test - public void testBasicsModules() throws BallerinaShellException { + public void testBasicsModules() { // TODO: Improve after custom classpath support testEvaluate(BASICS_MODULES_TESTCASE); } @Test - public void testBasicsVariables() throws BallerinaShellException { + public void testBasicsVariables() { testEvaluate(BASICS_VARIABLES_TESTCASE); } @Test - public void testEvaluateBasicsVar() throws BallerinaShellException { + public void testEvaluateBasicsVar() { testEvaluate(BASICS_VAR_TESTCASE); } @Test - public void testEvaluateBasicsFunctions() throws BallerinaShellException { + public void testEvaluateBasicsFunctions() { testEvaluate(BASICS_FUNCTIONS_TESTCASE); } @Test - public void testEvaluateBasicsReqParams() throws BallerinaShellException { + public void testEvaluateBasicsReqParams() { testEvaluate(BASICS_REQ_PARAMS_TESTCASE); } @Test - public void testEvaluateBasicsDefParams() throws BallerinaShellException { + public void testEvaluateBasicsDefParams() { testEvaluate(BASICS_DEF_PARAMS_TESTCASE); } @Test - public void testEvaluateBasicsRestParams() throws BallerinaShellException { + public void testEvaluateBasicsRestParams() { testEvaluate(BASICS_REST_PARAMS_TESTCASE); } @Test - public void testEvaluateBasicsQuoted() throws BallerinaShellException { + public void testEvaluateBasicsQuoted() { testEvaluate(BASICS_QUOTED_TESTCASE); } @Test - public void testEvaluateBasicsErrors() throws BallerinaShellException { + public void testEvaluateBasicsErrors() { testEvaluate(BASICS_ERRORS_TESTCASE); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/BehaviorTypeEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/BehaviorTypeEvaluatorTest.java index 186a04659804..8475cfad06a0 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/BehaviorTypeEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/BehaviorTypeEvaluatorTest.java @@ -18,7 +18,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -30,7 +29,7 @@ public class BehaviorTypeEvaluatorTest extends AbstractEvaluatorTest { private static final String STREAM_EVALUATOR_TESTCASE = "testcases/evaluator/streams.streams.json"; @Test - public void testEvaluateSteams() throws BallerinaShellException { + public void testEvaluateSteams() { testEvaluate(STREAM_EVALUATOR_TESTCASE); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/ConcurrencyEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/ConcurrencyEvaluatorTest.java index 63696365ec4a..76dcdb07a93b 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/ConcurrencyEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/ConcurrencyEvaluatorTest.java @@ -18,7 +18,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -31,7 +30,7 @@ public class ConcurrencyEvaluatorTest extends AbstractEvaluatorTest { private static final String LOCK_EVALUATOR_TESTCASE = "testcases/evaluator/concurrency.lock.json"; @Test - public void testEvaluateLock() throws BallerinaShellException { + public void testEvaluateLock() { testEvaluate(LOCK_EVALUATOR_TESTCASE); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/ErrorsEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/ErrorsEvaluatorTest.java index 33230be8957a..a41c1afbe5dd 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/ErrorsEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/ErrorsEvaluatorTest.java @@ -18,7 +18,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -37,42 +36,42 @@ public class ErrorsEvaluatorTest extends AbstractEvaluatorTest { private static final String SINGLE_PLACE_EVALUATOR_TESTCASE = "testcases/evaluator/errors.single.place.json"; @Test - public void testEvaluateErrorHandling() throws BallerinaShellException { + public void testEvaluateErrorHandling() { testEvaluate(HANDLING_EVALUATOR_TESTCASE); } @Test - public void testEvaluateFail() throws BallerinaShellException { + public void testEvaluateFail() { testEvaluate(FAIL_EVALUATOR_TESTCASE); } @Test - public void testEvaluateCheck() throws BallerinaShellException { + public void testEvaluateCheck() { testEvaluate(CHECK_EVALUATOR_TESTCASE); } @Test - public void testEvaluatePanic() throws BallerinaShellException { + public void testEvaluatePanic() { testEvaluate(PANIC_EVALUATOR_TESTCASE); } @Test - public void testEvaluateCheckPanic() throws BallerinaShellException { + public void testEvaluateCheckPanic() { testEvaluate(CHECKPANIC_EVALUATOR_TESTCASE); } @Test - public void testEvaluateTrap() throws BallerinaShellException { + public void testEvaluateTrap() { testEvaluate(TRAP_EVALUATOR_TESTCASE); } @Test - public void testEvaluateUserDef() throws BallerinaShellException { + public void testEvaluateUserDef() { testEvaluate(USER_DEF_EVALUATOR_TESTCASE); } @Test - public void testEvaluateSinglePlace() throws BallerinaShellException { + public void testEvaluateSinglePlace() { // TODO: Test transaction on fail clause testEvaluate(SINGLE_PLACE_EVALUATOR_TESTCASE); } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/FileEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/FileEvaluatorTest.java index 38a7ea382c39..a29da0dc19c9 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/FileEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/FileEvaluatorTest.java @@ -32,22 +32,22 @@ public class FileEvaluatorTest extends AbstractEvaluatorTest { private static final String RECURSIVE_EVALUATOR_TESTCASE = "testcases/evaluator/files.mu.recursive.json"; @Test - public void testEvaluateFileBasic() throws Exception { + public void testEvaluateFileBasic() { testEvaluate(BASIC_EVALUATOR_TESTCASE); } @Test - public void testEvaluateFileUnordered() throws Exception { + public void testEvaluateFileUnordered() { testEvaluate(UNORDERED_EVALUATOR_TESTCASE); } @Test - public void testEvaluateFileMutuallyUsed() throws Exception { + public void testEvaluateFileMutuallyUsed() { testEvaluate(MU_USED_EVALUATOR_TESTCASE); } @Test - public void testEvaluateFileRecursive() throws Exception { + public void testEvaluateFileRecursive() { testEvaluate(RECURSIVE_EVALUATOR_TESTCASE); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/FlowControlEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/FlowControlEvaluatorTest.java index 22dcb92f7198..431f6c9e3501 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/FlowControlEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/FlowControlEvaluatorTest.java @@ -18,7 +18,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -34,27 +33,27 @@ public class FlowControlEvaluatorTest extends AbstractEvaluatorTest { private static final String FOREACH_EVALUATOR_TESTCASE = "testcases/evaluator/flow.control.foreach.json"; @Test - public void testEvaluateElvis() throws BallerinaShellException { + public void testEvaluateElvis() { testEvaluate(ELVIS_EVALUATOR_TESTCASE); } @Test - public void testEvaluateIf() throws BallerinaShellException { + public void testEvaluateIf() { testEvaluate(IF_EVALUATOR_TESTCASE); } @Test - public void testEvaluateMatch() throws BallerinaShellException { + public void testEvaluateMatch() { testEvaluate(MATCH_EVALUATOR_TESTCASE); } @Test - public void testEvaluateWhile() throws BallerinaShellException { + public void testEvaluateWhile() { testEvaluate(WHILE_EVALUATOR_TESTCASE); } @Test - public void testEvaluateForEach() throws BallerinaShellException { + public void testEvaluateForEach() { testEvaluate(FOREACH_EVALUATOR_TESTCASE); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/FunctionEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/FunctionEvaluatorTest.java index 023968a382f9..a7ab6d452469 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/FunctionEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/FunctionEvaluatorTest.java @@ -18,7 +18,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -33,22 +32,22 @@ public class FunctionEvaluatorTest extends AbstractEvaluatorTest { private static final String POINTERS_EVALUATOR_TESTCASE = "testcases/evaluator/function.pointers.json"; @Test - public void testEvaluateAnonFn() throws BallerinaShellException { + public void testEvaluateAnonFn() { testEvaluate(ANON_EVALUATOR_TESTCASE); } @Test - public void testEvaluateExprBody() throws BallerinaShellException { + public void testEvaluateExprBody() { testEvaluate(EXPR_BODY_EVALUATOR_TESTCASE); } @Test - public void testEvaluateIterations() throws BallerinaShellException { + public void testEvaluateIterations() { testEvaluate(ITERATION_EVALUATOR_TESTCASE); } @Test - public void testEvaluatePointers() throws BallerinaShellException { + public void testEvaluatePointers() { testEvaluate(POINTERS_EVALUATOR_TESTCASE); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/JavaInteropEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/JavaInteropEvaluatorTest.java index 94602c8bef9d..a2a26b609e8e 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/JavaInteropEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/JavaInteropEvaluatorTest.java @@ -18,7 +18,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -30,7 +29,7 @@ public class JavaInteropEvaluatorTest extends AbstractEvaluatorTest { private static final String JAVA_INTEROP_EVALUATOR_TESTCASE = "testcases/evaluator/java.interop.json"; @Test - public void testEvaluateJavaInterop() throws BallerinaShellException { + public void testEvaluateJavaInterop() { testEvaluate(JAVA_INTEROP_EVALUATOR_TESTCASE); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/JsonXmlEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/JsonXmlEvaluatorTest.java index 8fbe296d099a..7f15cff0a001 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/JsonXmlEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/JsonXmlEvaluatorTest.java @@ -18,7 +18,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -40,57 +39,57 @@ public class JsonXmlEvaluatorTest extends AbstractEvaluatorTest { private static final String FUNCTION_EVALUATOR_TESTCASE = "testcases/evaluator/xml.function.json"; @Test - public void testEvaluateJson() throws BallerinaShellException { + public void testEvaluateJson() { testEvaluate(JSON_EVALUATOR_TESTCASE); } @Test - public void testEvaluateJsonObjects() throws BallerinaShellException { + public void testEvaluateJsonObjects() { testEvaluate(JSON_OBJECTS_EVALUATOR_TESTCASE); } @Test - public void testEvaluateJsonArrays() throws BallerinaShellException { + public void testEvaluateJsonArrays() { testEvaluate(JSON_ARRAYS_EVALUATOR_TESTCASE); } @Test - public void testEvaluateJsonAccess() throws BallerinaShellException { + public void testEvaluateJsonAccess() { testEvaluate(JSON_ACCESS_EVALUATOR_TESTCASE); } @Test - public void testEvaluateJsonConvertMap() throws BallerinaShellException { + public void testEvaluateJsonConvertMap() { testEvaluate(JSON_CONV_MAP_EVALUATOR_TESTCASE); } @Test - public void testEvaluateXml() throws BallerinaShellException { + public void testEvaluateXml() { testEvaluate(XML_EVALUATOR_TESTCASE); } @Test - public void testEvaluateXmlLiteral() throws BallerinaShellException { + public void testEvaluateXmlLiteral() { testEvaluate(LITERAL_EVALUATOR_TESTCASE); } @Test - public void testEvaluateXmlAttribute() throws BallerinaShellException { + public void testEvaluateXmlAttribute() { testEvaluate(ATTRIBUTE_EVALUATOR_TESTCASE); } @Test - public void testEvaluateXmlNamespace() throws BallerinaShellException { + public void testEvaluateXmlNamespace() { testEvaluate(NAMESPACE_EVALUATOR_TESTCASE); } @Test - public void testEvaluateXmlAccess() throws BallerinaShellException { + public void testEvaluateXmlAccess() { testEvaluate(ACCESS_EVALUATOR_TESTCASE); } @Test - public void testEvaluateXmlFunction() throws BallerinaShellException { + public void testEvaluateXmlFunction() { testEvaluate(FUNCTION_EVALUATOR_TESTCASE); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/MiscEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/MiscEvaluatorTest.java index 05ad8a7863e3..5d7718b00986 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/MiscEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/MiscEvaluatorTest.java @@ -18,7 +18,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -32,17 +31,17 @@ public class MiscEvaluatorTest extends AbstractEvaluatorTest { private static final String LET_EVALUATOR_TESTCASE = "testcases/evaluator/values.let.json"; @Test - public void testEvaluateEnum() throws BallerinaShellException { + public void testEvaluateEnum() { testEvaluate(ENUM_EVALUATOR_TESTCASE); } @Test - public void testEvaluateRawTemplate() throws BallerinaShellException { + public void testEvaluateRawTemplate() { testEvaluate(RAW_TEMP_EVALUATOR_TESTCASE); } @Test - public void testEvaluateLet() throws BallerinaShellException { + public void testEvaluateLet() { testEvaluate(LET_EVALUATOR_TESTCASE); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/ObjectEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/ObjectEvaluatorTest.java index 42df133e2986..2184cd06e819 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/ObjectEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/ObjectEvaluatorTest.java @@ -18,7 +18,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -37,42 +36,42 @@ public class ObjectEvaluatorTest extends AbstractEvaluatorTest { private static final String REF_EVALUATOR_TESTCASE = "testcases/evaluator/object.ref.json"; @Test - public void testEvaluateClass() throws BallerinaShellException { + public void testEvaluateClass() { testEvaluate(CLASS_EVALUATOR_TESTCASE); } @Test - public void testEvaluateInit() throws BallerinaShellException { + public void testEvaluateInit() { testEvaluate(INIT_EVALUATOR_TESTCASE); } @Test - public void testEvaluateMethod() throws BallerinaShellException { + public void testEvaluateMethod() { testEvaluate(METHODS_EVALUATOR_TESTCASE); } @Test - public void testEvaluateAssign() throws BallerinaShellException { + public void testEvaluateAssign() { testEvaluate(ASSIGN_EVALUATOR_TESTCASE); } @Test - public void testEvaluateType() throws BallerinaShellException { + public void testEvaluateType() { testEvaluate(TYPE_EVALUATOR_TESTCASE); } @Test - public void testEvaluateConstructor() throws BallerinaShellException { + public void testEvaluateConstructor() { testEvaluate(CONSTRUCTOR_EVALUATOR_TESTCASE); } @Test - public void testEvaluateReadonly() throws BallerinaShellException { + public void testEvaluateReadonly() { testEvaluate(READONLY_EVALUATOR_TESTCASE); } @Test - public void testEvaluateRef() throws BallerinaShellException { + public void testEvaluateRef() { testEvaluate(REF_EVALUATOR_TESTCASE); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/OperationsEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/OperationsEvaluatorTest.java index aab1009c0786..b86ed8cb3abb 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/OperationsEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/OperationsEvaluatorTest.java @@ -18,7 +18,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -39,52 +38,52 @@ public class OperationsEvaluatorTest extends AbstractEvaluatorTest { private static final String CONV_OPERATION_TESTCASE = "testcases/evaluator/operations.conv.json"; @Test - public void testEvaluateShift() throws BallerinaShellException { + public void testEvaluateShift() { testEvaluate(SHIFT_OPERATION_TESTCASE); } @Test - public void testEvaluateBitwise() throws BallerinaShellException { + public void testEvaluateBitwise() { testEvaluate(BITWISE_OPERATION_TESTCASE); } @Test - public void testEvaluateCompound() throws BallerinaShellException { + public void testEvaluateCompound() { testEvaluate(COMPOUND_OPERATION_TESTCASE); } @Test - public void testEvaluateEquality() throws BallerinaShellException { + public void testEvaluateEquality() { testEvaluate(EQUALITY_OPERATION_TESTCASE); } @Test - public void testEvaluateLength() throws BallerinaShellException { + public void testEvaluateLength() { testEvaluate(LENGTH_OPERATION_TESTCASE); } @Test - public void testEvaluateCast() throws BallerinaShellException { + public void testEvaluateCast() { testEvaluate(CAST_OPERATION_TESTCASE); } @Test - public void testEvaluateOptional() throws BallerinaShellException { + public void testEvaluateOptional() { testEvaluate(OPTIONAL_OPERATION_TESTCASE); } @Test - public void testEvaluateClone() throws BallerinaShellException { + public void testEvaluateClone() { testEvaluate(CLONE_OPERATION_TESTCASE); } @Test - public void testEvaluateImmutable() throws BallerinaShellException { + public void testEvaluateImmutable() { testEvaluate(IMMUTABLE_OPERATION_TESTCASE); } @Test - public void testEvaluateConvertTypes() throws BallerinaShellException { + public void testEvaluateConvertTypes() { testEvaluate(CONV_OPERATION_TESTCASE); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/PatternEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/PatternEvaluatorTest.java index 0d90ab6de769..c2bdfaa74a2a 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/PatternEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/PatternEvaluatorTest.java @@ -18,7 +18,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -32,17 +31,17 @@ public class PatternEvaluatorTest extends AbstractEvaluatorTest { private static final String ARRAY_EVALUATOR_TESTCASE = "testcases/evaluator/pattern.array.json"; @Test - public void testEvaluateTuple() throws BallerinaShellException { + public void testEvaluateTuple() { testEvaluate(TUPLE_EVALUATOR_TESTCASE); } @Test - public void testEvaluateRecord() throws BallerinaShellException { + public void testEvaluateRecord() { testEvaluate(RECORD_EVALUATOR_TESTCASE); } @Test - public void testEvaluateArray() throws BallerinaShellException { + public void testEvaluateArray() { testEvaluate(ARRAY_EVALUATOR_TESTCASE); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/QueryEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/QueryEvaluatorTest.java index 2d31d6a2d227..477c503bebd8 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/QueryEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/QueryEvaluatorTest.java @@ -18,7 +18,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -33,19 +32,19 @@ public class QueryEvaluatorTest extends AbstractEvaluatorTest { private static final String QUERY_ACTION_EVALUATOR_TESTCASE = "testcases/evaluator/query.action.json"; @Test - public void testEvaluateQueryExpr() throws BallerinaShellException { + public void testEvaluateQueryExpr() { // TODO: (#28389) Compiler crashes for module-level query expression which uses var testEvaluate(QUERY_EXPR_EVALUATOR_TESTCASE); } @Test - public void testEvaluateQueryJoin() throws BallerinaShellException { + public void testEvaluateQueryJoin() { // TODO: (#28390) Module-level query expressions don't work testEvaluate(QUERY_JOIN_EVALUATOR_TESTCASE); } @Test - public void testEvaluateQueryAction() throws BallerinaShellException { + public void testEvaluateQueryAction() { testEvaluate(QUERY_ACTION_EVALUATOR_TESTCASE); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/RecordEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/RecordEvaluatorTest.java index c197d032e3ba..8baad7a258fa 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/RecordEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/RecordEvaluatorTest.java @@ -18,7 +18,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -34,27 +33,27 @@ public class RecordEvaluatorTest extends AbstractEvaluatorTest { private static final String READONLY_TESTCASE = "testcases/evaluator/record.readonly.json"; @Test - public void testRecordBasic() throws BallerinaShellException { + public void testRecordBasic() { testEvaluate(RECORD_TESTCASE); } @Test - public void testRecordAnon() throws BallerinaShellException { + public void testRecordAnon() { testEvaluate(ANON_TESTCASE); } @Test - public void testRecordOptional() throws BallerinaShellException { + public void testRecordOptional() { testEvaluate(OPTIONAL_TESTCASE); } @Test - public void testRecordRef() throws BallerinaShellException { + public void testRecordRef() { testEvaluate(REF_TESTCASE); } @Test - public void testRecordReadonly() throws BallerinaShellException { + public void testRecordReadonly() { testEvaluate(READONLY_TESTCASE); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/RegressionEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/RegressionEvaluatorTest.java index f4551ecd94c4..91c028611fcc 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/RegressionEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/RegressionEvaluatorTest.java @@ -18,7 +18,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -34,31 +33,31 @@ public class RegressionEvaluatorTest extends AbstractEvaluatorTest { private static final String IMPORT_CYCLIC_TYPE_TESTCASE = "testcases/evaluator/regression.cyclic.type.json"; @Test - public void testEvaluateSameImport() throws BallerinaShellException { + public void testEvaluateSameImport() { // Import can be again and again imported with same prefix. testEvaluate(SAME_IMPORT_EVALUATOR_TESTCASE); } @Test - public void testEvaluateImportUsedFn() throws BallerinaShellException { + public void testEvaluateImportUsedFn() { // Functions using imports are correctly processed. testEvaluate(IMPORT_USED_FN_TESTCASE); } @Test - public void testEvaluateQualifiers() throws BallerinaShellException { + public void testEvaluateQualifiers() { // Test for qualifiers use. testEvaluate(QUALIFIERS_TESTCASE); } @Test - public void testEvaluatePanicSaveState() throws BallerinaShellException { + public void testEvaluatePanicSaveState() { // Check if panic correctly preserves state. testEvaluate(PANIC_SAVE_STATE_TESTCASE); } @Test - public void testEvaluateCyclicType() throws BallerinaShellException { + public void testEvaluateCyclicType() { // Cyclic types use. testEvaluate(IMPORT_CYCLIC_TYPE_TESTCASE); } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/SimpleEvaluatorTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/SimpleEvaluatorTest.java index 59873b2fd5ab..aad6e24864df 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/SimpleEvaluatorTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/SimpleEvaluatorTest.java @@ -18,7 +18,6 @@ package io.ballerina.shell.test.evaluator; -import io.ballerina.shell.exceptions.BallerinaShellException; import org.testng.annotations.Test; /** @@ -31,12 +30,12 @@ public class SimpleEvaluatorTest extends AbstractEvaluatorTest { private static final String LITERALS_EVALUATOR_TESTCASE = "testcases/evaluator/values.literals.json"; @Test - public void testEvaluateBasic() throws BallerinaShellException { + public void testEvaluateBasic() { testEvaluate(BASIC_EVALUATOR_TESTCASE); } @Test - public void testEvaluateLiterals() throws BallerinaShellException { + public void testEvaluateLiterals() { testEvaluate(LITERALS_EVALUATOR_TESTCASE); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/base/TestInvoker.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/base/TestInvoker.java index 9de86a064d2d..86b23ef6ca5c 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/base/TestInvoker.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/evaluator/base/TestInvoker.java @@ -61,6 +61,7 @@ public String getStdOut() { return output.replace("\r\n", "\n"); } + @Override public void reset() { this.stdOutBaOs.reset(); } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/unit/EvaluatorMiscTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/unit/EvaluatorMiscTest.java index 91356a2eae12..bded26f3afd6 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/unit/EvaluatorMiscTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/unit/EvaluatorMiscTest.java @@ -31,7 +31,6 @@ import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; /** * Misc functionality testing of evaluator. @@ -169,6 +168,6 @@ private List filterAvailableVariables(Evaluator evaluator) { return evaluator.availableVariables().stream().filter(s -> !s.equals("Variable declarations") && !s.equals("Final variable declarations") && !s.equals("Constant Variable Declarations")) - .collect(Collectors.toList()); + .toList(); } } diff --git a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/unit/StringUtilsTest.java b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/unit/StringUtilsTest.java index 91e78018493c..708c43620cf2 100644 --- a/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/unit/StringUtilsTest.java +++ b/ballerina-shell/modules/shell-core/src/test/java/io/ballerina/shell/test/unit/StringUtilsTest.java @@ -51,18 +51,18 @@ public void testShortenedString() { @Test public void testHighlightDiagnostic() { - testHighlightDiagnostic("int i = 100", "" + - "error: missing semicolon token\n" + - "\tint i = 100\n" + - "\t ^"); - testHighlightDiagnostic("int i\\-\\like\\-hyphens = 100", "" + - "error: invalid escape sequence '\\l'\n" + - "\tint i\\-\\like\\-hyphens = 100\n" + - "\t ^---------------^"); - testHighlightDiagnostic("\\l", "" + - "error: invalid escape sequence '\\l'\n" + - "\t\\l\n" + - "\t^^"); + testHighlightDiagnostic("int i = 100", """ + error: missing semicolon token + \tint i = 100 + \t ^"""); + testHighlightDiagnostic("int i\\-\\like\\-hyphens = 100", """ + error: invalid escape sequence '\\l' + \tint i\\-\\like\\-hyphens = 100 + \t ^---------------^"""); + testHighlightDiagnostic("\\l", """ + error: invalid escape sequence '\\l' + \t\\l + \t^^"""); } private void testHighlightDiagnostic(String code, String expectedError) { diff --git a/ballerina-shell/modules/shell-rt/build.gradle b/ballerina-shell/modules/shell-rt/build.gradle index e06201d59108..de913a58cbc0 100644 --- a/ballerina-shell/modules/shell-rt/build.gradle +++ b/ballerina-shell/modules/shell-rt/build.gradle @@ -16,15 +16,17 @@ * under the License. */ -apply from: "$rootDir/gradle/javaProject.gradle" -apply from: "$rootDir/gradle/ballerinaLangLibLoad.gradle" +plugins { + id 'javaProject' + id 'ballerinaLangLibLoad' +} description = 'Ballerina - Ballerina Shell Runtime Dependencies' group = 'io.ballerina' dependencies { - testImplementation('org.testng:testng') + testImplementation libs.testng } test { diff --git a/ballerina-shell/modules/shell-rt/src/main/java/io/ballerina/shell/rt/InvokerMemory.java b/ballerina-shell/modules/shell-rt/src/main/java/io/ballerina/shell/rt/InvokerMemory.java index 82d5f4061812..676a57420a1d 100644 --- a/ballerina-shell/modules/shell-rt/src/main/java/io/ballerina/shell/rt/InvokerMemory.java +++ b/ballerina-shell/modules/shell-rt/src/main/java/io/ballerina/shell/rt/InvokerMemory.java @@ -28,10 +28,14 @@ * * @since 2.0.0 */ -public class InvokerMemory { +public final class InvokerMemory { + private static final String QUOTE = "'"; private static final HashMap> memory = new HashMap<>(); + private InvokerMemory() { + } + /** * Recalls the variable value. * This will return null if variable is not cached. diff --git a/benchmarks/build.gradle b/benchmarks/build.gradle index d15f366b9a8d..40672a9545c8 100644 --- a/benchmarks/build.gradle +++ b/benchmarks/build.gradle @@ -14,12 +14,14 @@ * limitations under the License. * */ - -apply from: "$rootDir/gradle/javaProject.gradle" + +plugins { + id 'javaProject' +} dependencies { // compile project(':ballerina') - implementation 'com.github.chewiebug:gcviewer' + implementation libs.chewiebug.gcviewer } description = 'Ballerina - Microbenchmarks' diff --git a/build-config/checkstyle/build.gradle b/build-config/checkstyle/build.gradle index 97a00b2e7df3..1187ab6f054d 100644 --- a/build-config/checkstyle/build.gradle +++ b/build-config/checkstyle/build.gradle @@ -3,7 +3,7 @@ plugins { id 'base' } -task downloadFile(type: Download) { +tasks.register('downloadFile', Download) { src([ 'https://github.com/raw/wso2/code-quality-tools/v1.4/checkstyle/jdk-17/checkstyle.xml', 'https://github.com/raw/wso2/code-quality-tools/v1.4/checkstyle/jdk-17/suppressions.xml' diff --git a/build.gradle b/build.gradle index ae45d2b35823..b1baae0578e4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,21 +1,24 @@ plugins { id 'base' - id "com.github.spotbugs" version "${githubSpotbugsVersion}" - id "com.dorongold.task-tree" version "${dorongoldTaskTreeVersion}" - id "com.github.johnrengelman.shadow" version "${githubJohnrengelmanShadowVersion}" + alias libs.plugins.spotbugs + alias libs.plugins.dorongold.task.tree + alias libs.plugins.github.johnrengelman.shadow id 'maven-publish' - id "net.researchgate.release" version "${researchgateReleaseVersion}" + alias libs.plugins.researchgate.release id 'jacoco' - id "org.sonarqube" version "${sonarqubeGradlePluginVersion}" + alias libs.plugins.sonarqube + id 'repositories' } -apply from: "$rootDir/gradle/repositories.gradle" - allprojects { + tasks.withType(JavaCompile).configureEach { + options.fork = true + } + group = project.group version = project.version - task printPath { + tasks.register('printPath') { doLast{ println projectDir } @@ -66,39 +69,54 @@ dependencies { def classFilesArray = [] def execFilesArray = [] +def skipDirectories = [ + "ballerina-gradle-plugins", // Gradle plugins + "jballerina-benchmark-test", // Benchmark test code + "lib-creator", // Gradle code for generate Bala files + "semtypes", // Tests are in nBallerina branch + "test-artifacts",// Tests directories for project api + "ballerina-lang/tests"// Ballerina Language Tests +] -task copyExecFilesAndJavaClassFiles { - subprojects.forEach { subproject -> - def execFile = new File("${subproject.buildDir}/jacoco/jacoco.exec") - if (execFile.exists()) { - execFilesArray.push(execFile) - fileTree("${subproject.buildDir}/classes").matching { - exclude '**/test/*' - exclude '**/module-info.class' - include '**/*.class' - }.each { file -> classFilesArray.push(file) } +tasks.register('copyExecFilesAndJavaClassFiles') { + subprojects.forEach { subproject -> + fileTree("${subproject.buildDir}/jacoco").matching { + include "**/*.exec" + }.each { + execFilesArray.push(it) + } + // Sources of modules used specifically for tests, gradle plugins are skipped + boolean skipProject = false + skipDirectories.forEach { dir -> + { + if (subproject.projectDir.path.contains(dir)) { + skipProject = true + return + } + } + } + if (skipProject) { + return + } + fileTree("${subproject.buildDir}/classes").matching { + exclude '**/java/test/**' + exclude '**/default/**' + exclude '**/module-info.class' + }.each { file -> + classFilesArray.push(file) } } } -task copyBallerinaClassFiles { - subprojects.forEach { subproject -> - def ballerinaSourceDirectory = new File("${subproject.buildDir}/ballerina-src") +tasks.register('copyBallerinaClassFiles') { + subprojects.forEach { subproject -> + def ballerinaSourceDirectory = new File("${subproject.buildDir}/ballerina-src") if (ballerinaSourceDirectory.exists() && subproject.projectDir.getParentFile().getName() == "langlib") { fileTree("${subproject.buildDir}/ballerina-src/target").include("**/*.zip").forEach { zip -> - def jarFiles = zipTree(zip).matching { include '**/*.jar' } + def jarFiles = zipTree(zip).matching { include '**/*.jar' } jarFiles.forEach { jar -> zipTree(jar).matching { exclude '**/tests/*' - exclude '**/$_init.class' - exclude '**/$value$Caller.class' - exclude '**/$value$Detail.class' - exclude '**/$value$DetailType.class' - exclude '**/$value$EmptyIterator.class' - exclude '**/$value$$anonType$_6.class' - exclude '**/$value$$anonType$_*.class' - exclude '**/$value$_Frame.class' - include '**/*.class' }.each { file -> classFilesArray.push(file) } } } @@ -106,7 +124,7 @@ task copyBallerinaClassFiles { } } -task createCodeCoverageReport(type: JacocoReport) { +tasks.register('createCodeCoverageReport', JacocoReport) { executionData files(execFilesArray) additionalClassDirs files(classFilesArray) reports { @@ -129,4 +147,3 @@ sonarqube { } copyBallerinaClassFiles.dependsOn copyExecFilesAndJavaClassFiles -createCodeCoverageReport.dependsOn copyBallerinaClassFiles diff --git a/bvm/ballerina-profiler/build.gradle b/bvm/ballerina-profiler/build.gradle index dd0b44fe5d35..936ad3d5e1ca 100644 --- a/bvm/ballerina-profiler/build.gradle +++ b/bvm/ballerina-profiler/build.gradle @@ -16,13 +16,19 @@ * under the License. */ -apply from: "$rootDir/gradle/javaProject.gradle" +plugins { + id 'javaProject' +} + +configurations { + runtimeClasspath.transitive = false +} dependencies { - implementation "org.ow2.asm:asm:${project.ow2AsmVersion}" - implementation "org.ow2.asm:asm-commons:${project.ow2AsmCommonsVersion}" - implementation "com.google.code.gson:gson:${project.gsonVersion}" - implementation "commons-io:commons-io:${project.commonsIoVersion}" + implementation libs.ow2.asm + implementation libs.ow2.asm.commons + implementation libs.gson + implementation libs.commons.io implementation project(':identifier-util') implementation project(':ballerina-runtime') } @@ -30,20 +36,8 @@ dependencies { version = 1.0 jar { - dependsOn(':identifier-util:jar') - dependsOn(':ballerina-runtime:jar') - from(sourceSets.main.output) - from(sourceSets.main.java) { - include "**/*.java" - } - - from(configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }) { - exclude "META-INF/*.SF" - exclude "META-INF/*.DSA" - exclude "META-INF/*.RSA" - } duplicatesStrategy = DuplicatesStrategy.EXCLUDE - + from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } manifest { attributes 'Main-Class': 'io.ballerina.runtime.profiler.Main' } diff --git a/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/Main.java b/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/Main.java index 54a66c4d805c..efbc0fbf4826 100644 --- a/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/Main.java +++ b/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/Main.java @@ -27,9 +27,13 @@ * * @since 2201.8.0 */ -public class Main { +public final class Main { + private static Profiler profiler; + private Main() { + } + public static void main(String[] args) throws ProfilerException { profiler = new Profiler(TimeUnit.MILLISECONDS.convert(System.nanoTime(), TimeUnit.NANOSECONDS)); profiler.start(args); diff --git a/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/Profiler.java b/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/Profiler.java index 38ce6b8dc788..2f35ad7a84ec 100644 --- a/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/Profiler.java +++ b/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/Profiler.java @@ -35,13 +35,11 @@ import java.net.URLClassLoader; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.jar.JarFile; import java.util.regex.Pattern; -import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -82,11 +80,11 @@ private void addShutdownHookAndCleanup() { try { long profilerTotalTime = TimeUnit.MILLISECONDS.convert(System.nanoTime(), TimeUnit.NANOSECONDS) - profilerStartTime; - Files.deleteIfExists(Paths.get(Constants.TEMP_JAR_FILE_NAME)); + Files.deleteIfExists(Path.of(Constants.TEMP_JAR_FILE_NAME)); OUT_STREAM.printf("%s[6/6] Generating output...%s%n", Constants.ANSI_CYAN, Constants.ANSI_RESET); JsonParser jsonParser = new JsonParser(); HttpServer httpServer = new HttpServer(); - String cpuFilePath = Paths.get(currentDir, CPU_PRE_JSON).toString(); + String cpuFilePath = Path.of(currentDir, CPU_PRE_JSON).toString(); jsonParser.initializeCPUParser(cpuFilePath); deleteFileIfExists(cpuFilePath); OUT_STREAM.printf(" Execution time: %d seconds %n", profilerTotalTime / 1000); @@ -105,7 +103,7 @@ private void deleteFileIfExists(String filePath) { return; } try { - Files.delete(Paths.get(filePath)); + Files.delete(Path.of(filePath)); } catch (IOException e) { throw new ProfilerException("Failed to delete file: " + filePath + "%n", e); } @@ -174,7 +172,7 @@ private void addToUsedArgs(String[] args, List usedArgs, int i) { private void extractProfiler() throws ProfilerException { OUT_STREAM.printf("%s[1/6] Initializing...%s%n", Constants.ANSI_CYAN, Constants.ANSI_RESET); try { - Path profilerRuntimePath = Paths.get("io/ballerina/runtime/profiler/runtime"); + Path profilerRuntimePath = Path.of("io/ballerina/runtime/profiler/runtime"); new ProcessBuilder("jar", "xvf", "Profiler.jar", profilerRuntimePath.toString()).start().waitFor(); } catch (IOException | InterruptedException exception) { throw new ProfilerException(exception); @@ -184,8 +182,8 @@ private void extractProfiler() throws ProfilerException { private void createTempJar() { try { OUT_STREAM.printf("%s[2/6] Copying executable...%s%n", Constants.ANSI_CYAN, Constants.ANSI_RESET); - Path sourcePath = Paths.get(balJarName); - Path destinationPath = Paths.get(Constants.TEMP_JAR_FILE_NAME); + Path sourcePath = Path.of(balJarName); + Path destinationPath = Path.of(Constants.TEMP_JAR_FILE_NAME); Files.copy(sourcePath, destinationPath); } catch (IOException e) { throw new ProfilerException("Error occurred while copying the file: " + balJarName, e); @@ -236,13 +234,13 @@ private void modifyJar() throws InterruptedException, IOException { final File userDirectory = new File(System.getProperty("user.dir")); // Get the user directory listAllFiles(userDirectory); // List all files in the user directory and its subdirectories // Get a list of the directories containing instrumented files - List changedDirectories = instrumentedFiles.stream().distinct().collect(Collectors.toList()); + List changedDirectories = instrumentedFiles.stream().distinct().toList(); loadDirectories(changedDirectories); } finally { for (String instrumentedFilePath : instrumentedPaths) { FileUtils.deleteDirectory(new File(instrumentedFilePath)); } - Path filePath = Paths.get("io/ballerina/runtime/profiler/runtime"); + Path filePath = Path.of("io/ballerina/runtime/profiler/runtime"); FileUtils.deleteDirectory(new File(filePath.toString())); profilerMethodWrapper.invokeMethods(profilerDebugArg); } @@ -259,7 +257,7 @@ private void loadDirectories(List changedDirs) { } private void listAllFiles(final File userDirectory) { - String absolutePath = Paths.get(Constants.TEMP_JAR_FILE_NAME).toFile().getAbsolutePath(); + String absolutePath = Path.of(Constants.TEMP_JAR_FILE_NAME).toFile().getAbsolutePath(); analyseInstrumentedDirectories(userDirectory, absolutePath.replaceAll(Constants.TEMP_JAR_FILE_NAME, "")); } diff --git a/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/codegen/ProfilerMethodWrapper.java b/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/codegen/ProfilerMethodWrapper.java index b2c4be7eab31..58b59c1b97e4 100644 --- a/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/codegen/ProfilerMethodWrapper.java +++ b/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/codegen/ProfilerMethodWrapper.java @@ -34,7 +34,7 @@ import java.net.URL; import java.net.URLClassLoader; import java.nio.charset.StandardCharsets; -import java.nio.file.Paths; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.jar.Attributes; @@ -52,21 +52,30 @@ */ public class ProfilerMethodWrapper extends ClassLoader { + public static final String JAVA_OPTS = "JAVA_OPTS"; + public void invokeMethods(String debugArg) throws IOException, InterruptedException { String balJarArgs = Main.getBalJarArgs(); List commands = new ArrayList<>(); + String javaOpts = System.getenv().get(JAVA_OPTS); commands.add(System.getenv("java.command")); + if (javaOpts != null) { + commands.add(javaOpts.trim()); + } commands.add("-jar"); if (debugArg != null) { commands.add(debugArg); } - commands.add(Paths.get(System.getProperty(USER_DIR), Constants.TEMP_JAR_FILE_NAME).toString()); + commands.add(Path.of(System.getProperty(USER_DIR), Constants.TEMP_JAR_FILE_NAME).toString()); if (balJarArgs != null) { commands.add(balJarArgs); } ProcessBuilder processBuilder = new ProcessBuilder(commands); processBuilder.inheritIO(); processBuilder.directory(new File(System.getenv(CURRENT_DIR_KEY))); + if (javaOpts != null) { + processBuilder.environment().put(JAVA_OPTS, javaOpts.trim()); + } Process process = processBuilder.start(); OUT_STREAM.printf(Constants.ANSI_CYAN + "[5/6] Running executable..." + Constants.ANSI_RESET + "%n"); try (InputStreamReader streamReader = new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8); diff --git a/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/runtime/StackTraceMap.java b/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/runtime/StackTraceMap.java index 8f208758e739..3160d9c7115b 100644 --- a/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/runtime/StackTraceMap.java +++ b/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/runtime/StackTraceMap.java @@ -28,7 +28,7 @@ * * @since 2201.8.0 */ -public class StackTraceMap { +public final class StackTraceMap { private static final AtomicInteger localVarIndex = new AtomicInteger(0); private static final ConcurrentHashMap stackTraceIndexMap = new ConcurrentHashMap<>(); @@ -62,6 +62,6 @@ static String getCallStackString(String stackKey) { } private static String decodeStackElement(String stackElement) { - return Utils.decodeIdentifier(stackElement.replaceAll("\\$value\\$", "")); + return Utils.decodeIdentifier(stackElement.replace("$value$", "")); } } diff --git a/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/ui/FileUtils.java b/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/ui/FileUtils.java index c7ebaa7f01da..8663592e4f8b 100644 --- a/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/ui/FileUtils.java +++ b/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/ui/FileUtils.java @@ -23,9 +23,8 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -public class FileUtils { +public final class FileUtils { // Maximum wait time for the file to be created. This will wait 600*100 ms = 60 s. private static final int MAX_WAIT_TIME_FOR_FILE = 600; @@ -34,7 +33,7 @@ private FileUtils() { } static String readFileAsString(String file) throws IOException { - Path path = Paths.get(file); + Path path = Path.of(file); int count = 0; while (!Files.exists(path)) { if (count++ > MAX_WAIT_TIME_FOR_FILE) { diff --git a/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/ui/FrontEnd.java b/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/ui/FrontEnd.java index 22eb789fc411..e83b0b8b528b 100644 --- a/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/ui/FrontEnd.java +++ b/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/ui/FrontEnd.java @@ -28,7 +28,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import static io.ballerina.runtime.profiler.util.Constants.BALLERINA_HOME; import static io.ballerina.runtime.profiler.util.Constants.HTML_TEMPLATE_FILE; @@ -52,7 +51,7 @@ String getSiteData(String contents) { } public String readFileAsString() throws IOException { - Path resourceFilePath = Paths.get(System.getenv(BALLERINA_HOME)).resolve("resources") + Path resourceFilePath = Path.of(System.getenv(BALLERINA_HOME)).resolve("resources") .resolve("profiler").resolve(HTML_TEMPLATE_FILE); if (!Files.exists(resourceFilePath)) { throw new ProfilerRuntimeException("resource file not found: " + HTML_TEMPLATE_FILE); diff --git a/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/ui/HttpServer.java b/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/ui/HttpServer.java index 8ea2d34844a6..1b2ab91e919c 100644 --- a/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/ui/HttpServer.java +++ b/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/ui/HttpServer.java @@ -29,7 +29,6 @@ import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; @@ -52,7 +51,7 @@ public void initializeHTMLExport() throws IOException { String profilerOutputDir = System.getProperty(WORKING_DIRECTORY); OUT_STREAM.printf(" Output: " + Constants.ANSI_YELLOW + "%s" + File.separator + HTML_PROFILER_REPORT + Constants.ANSI_RESET + "%n", profilerOutputDir); - Path resourcePath = Paths.get(System.getenv(BALLERINA_HOME)).resolve("resources") + Path resourcePath = Path.of(System.getenv(BALLERINA_HOME)).resolve("resources") .resolve("profiler"); try { diff --git a/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/util/Constants.java b/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/util/Constants.java index ff30884b8ab1..af3f6811bc10 100644 --- a/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/util/Constants.java +++ b/bvm/ballerina-profiler/src/main/java/io/ballerina/runtime/profiler/util/Constants.java @@ -25,7 +25,8 @@ * * @since 2201.8.0 */ -public class Constants { +public final class Constants { + public static final String ANSI_RESET = "\u001B[0m"; public static final String ANSI_GRAY = "\033[37m"; public static final String ANSI_CYAN = "\033[1;38;2;32;182;176m"; diff --git a/bvm/ballerina-rt/build.gradle b/bvm/ballerina-rt/build.gradle index 94da5e8160ce..3a154c91c299 100644 --- a/bvm/ballerina-rt/build.gradle +++ b/bvm/ballerina-rt/build.gradle @@ -19,10 +19,9 @@ plugins { id 'java-library' id 'checkstyle' id 'com.github.spotbugs' + id 'repositories' } -apply from: "$rootDir/gradle/repositories.gradle" - configurations { dist { transitive false @@ -85,39 +84,38 @@ dependencies { // Third party jars // config - dist "org.slf4j:slf4j-jdk14:${project.slf4jJdk14Version}" - dist "org.slf4j:slf4j-api:${project.slf4jApiVersion}" - dist "org.apache.commons:commons-lang3:${project.apacheCommonsLang3Version}" - dist "org.apache.commons:commons-text:${project.apacheCommonsTextVersion}" - dist "com.moandjiezana.toml:toml4j:${project.moandjiezanaToml4jVersion}" - dist "com.fasterxml.woodstox:woodstox-core:${project.fasterxmlWoodstoxCoreVersion}" - dist "org.codehaus.woodstox:stax2-api:${project.codehausWoodstoxStax2ApiVersion}" + dist libs.slf4j.jdk14 + dist libs.slf4j.api + dist libs.apache.commons.lang3 + dist libs.apache.commons.text + dist libs.toml4j + dist libs.fasterxml.woodstox.core + dist libs.codehaus.woodstox.stax2.api // runtime - dist "org.apache.ws.commons.axiom:axiom-c14n:${project.apacheCommonsAxiomC14nVersion}" - dist "org.apache.ws.commons.axiom:axiom-impl:${project.apacheCommonsAxiomImplVersion}" - dist "org.apache.ws.commons.axiom:axiom-api:${project.apacheCommonsAxiomApiVersion}" - dist "org.apache.ws.commons.axiom:axiom-dom:${project.apacheCommonsAxiomDomVersion}" - dist "commons-logging:commons-logging:${project.commonsLoggingVersion}" - dist "io.opentelemetry:opentelemetry-api:${project.openTelemetryApiVersion}" - dist "io.opentelemetry:opentelemetry-context:${project.openTelemetryContextVersion}" - dist "org.awaitility:awaitility:${project.awaitilityVersion}" - dist "org.hdrhistogram:HdrHistogram:${project.hdrHistogramVersion}" + dist libs.apache.commons.axiom.c14n + dist libs.apache.commons.axiom.impl + dist libs.apache.commons.axiom.api + dist libs.apache.commons.axiom.dom + dist libs.commons.logging + dist libs.open.telemetry.api + dist libs.open.telemetry.context + dist libs.awaitility + dist libs.hdr.histogram // observability extensions //// metrics dist project(':metrics-extensions:ballerina-metrics-extension') - // Temporary adding . Need to Remove once fix #17878 - dist "com.google.code.gson:gson:${project.gsonVersion}" + dist libs.gson // Transaction related third party jars - dist "com.atomikos:transactions-jta:${project.atomikosTransactionsJtaVersion}" - dist "com.atomikos:atomikos-util:${project.atomikosUtilVersion}" - dist "com.atomikos:transactions-api:${project.atomikosTransactionsApiVersion}" - dist "com.atomikos:transactions-jdbc:${project.atomikosTransactionsJdbcVersion}" - dist "com.atomikos:transactions:${project.atomikosTransactionsVersion}" - dist "javax.transaction:javax.transaction-api:${project.javaxTransactionApiVersion}" + dist libs.atomikos.transactions.jta + dist libs.atomikos.util + dist libs.atomikos.transactions.api + dist libs.atomikos.transactions.jdbc + dist libs.atomikos.transactions + dist libs.javax.transaction.api // debugger runtime helpers dist project(':debug-adapter:debug-adapter-runtime') diff --git a/bvm/ballerina-runtime/build.gradle b/bvm/ballerina-runtime/build.gradle index 05fdf36a7b20..2a72c674af89 100644 --- a/bvm/ballerina-runtime/build.gradle +++ b/bvm/ballerina-runtime/build.gradle @@ -15,30 +15,32 @@ * */ -apply from: "$rootDir/gradle/javaProject.gradle" +plugins { + id 'javaProject' +} dependencies { - implementation("org.apache.ws.commons.axiom:axiom-impl:${project.apacheCommonsAxiomImplVersion}") { + implementation(libs.apache.commons.axiom.impl) { exclude group: 'org.apache.ws.commons.axiom', module: 'axiom-api' } - implementation('org.apache.ws.commons.axiom:axiom-api') { + implementation(libs.apache.commons.axiom.api) { exclude group: 'org.apache.geronimo.specs', module: 'geronimo-stax-api_1.0_spec' exclude group: 'jaxen', module: 'jaxen' } - implementation 'org.apache.commons:commons-text' - implementation 'io.opentelemetry:opentelemetry-api' - implementation("com.atomikos:transactions-jta:${project.atomikosTransactionsJtaVersion}") { + implementation libs.apache.commons.text + implementation libs.open.telemetry.api + implementation(libs.atomikos.transactions.jta) { exclude group: 'org.hibernate', module: 'hibernate' } - implementation "javax.transaction:javax.transaction-api:${project.javaxTransactionApiVersion}" + implementation libs.javax.transaction.api implementation project(':toml-parser') implementation project(':ballerina-tools-api') implementation project(':identifier-util') - testImplementation 'org.testng:testng' - testImplementation "org.mockito:mockito-core:${project.mockitoCoreVersion}" - testImplementation 'org.mockito:mockito-testng' + testImplementation libs.testng + testImplementation libs.mockito.core + testImplementation libs.mockito.testng } @@ -67,9 +69,14 @@ ext.moduleName = 'ballerina.runtime' compileJava { inputs.property("moduleName", moduleName) doFirst { - options.compilerArgs = [ - '--module-path', classpath.asPath, - ] + options.compilerArgs << '--module-path' << classpath.asPath + classpath = files() + } +} + +javadoc { + doFirst { + options.modulePath = classpath.toList() classpath = files() } } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/PredefinedTypes.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/PredefinedTypes.java index 2dc13a546404..3d0c7e49e7d5 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/PredefinedTypes.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/PredefinedTypes.java @@ -87,7 +87,7 @@ * * @since 2.0.0 */ -public class PredefinedTypes { +public final class PredefinedTypes { private static final Module EMPTY_MODULE = new Module(null, null, null); @@ -245,7 +245,7 @@ private static BAnydataType getAnydataType(List members, String typeName, ArrayList members = new ArrayList<>(); members.add(TYPE_XML); members.add(TYPE_READONLY); - var valueModule = new Module(BALLERINA_BUILTIN_PKG_PREFIX, VALUE_LANG_LIB, null); + Module valueModule = new Module(BALLERINA_BUILTIN_PKG_PREFIX, VALUE_LANG_LIB, null); BUnionType cloneable = new BUnionType(TypeConstants.CLONEABLE_TNAME, valueModule, members, false); cloneable.isCyclic = true; MapType internalCloneableMap = new BMapType(TypeConstants.MAP_TNAME, cloneable, valueModule); @@ -266,7 +266,7 @@ private static BAnydataType getAnydataType(List members, String typeName, members.add(TYPE_BOOLEAN); members.add(TYPE_STRING); members.add(TYPE_DECIMAL); - var valueModule = new Module(BALLERINA_BUILTIN_PKG_PREFIX, VALUE_LANG_LIB, null); + Module valueModule = new Module(BALLERINA_BUILTIN_PKG_PREFIX, VALUE_LANG_LIB, null); BUnionType jsonDecimal = new BUnionType(TypeConstants.JSON_DECIMAL_TNAME, valueModule, members, false); jsonDecimal.isCyclic = true; MapType internalJsonDecimalMap = new BMapType(TypeConstants.MAP_TNAME, jsonDecimal, valueModule); @@ -282,7 +282,7 @@ private static BAnydataType getAnydataType(List members, String typeName, members.add(TYPE_BOOLEAN); members.add(TYPE_STRING); members.add(TYPE_FLOAT); - var valueModule = new Module(BALLERINA_BUILTIN_PKG_PREFIX, VALUE_LANG_LIB, null); + Module valueModule = new Module(BALLERINA_BUILTIN_PKG_PREFIX, VALUE_LANG_LIB, null); BUnionType jsonFloat = new BUnionType(TypeConstants.JSON_FLOAT_TNAME, valueModule, members, false); jsonFloat.isCyclic = true; MapType internalJsonFloatMap = new BMapType(TypeConstants.MAP_TNAME, jsonFloat, valueModule); diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/Repository.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/Repository.java index 5ddbfe65ee31..af4f803c91c6 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/Repository.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/Repository.java @@ -29,11 +29,17 @@ public interface Repository { * Get the list of runtime artifacts. * @return List of artifacts that contains information about the active services and listeners. */ - public List getArtifacts(); + List getArtifacts(); /** * Get the current Ballerina node. * @return Ballerina node. */ - public Node getNode(); + Node getNode(); + + /** + * Get whether remote management is enabled. + * @return True if remote management is enabled, false otherwise. + */ + boolean isRemoteManagementEnabled(); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/Runtime.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/Runtime.java index 35f0117085f9..186331ad0e6d 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/Runtime.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/Runtime.java @@ -178,7 +178,7 @@ public abstract Object invokeMethodAsync(BObject object, String methodName, Stri public abstract void deregisterListener(BObject listener); - public abstract void registerStopHandler(BFunctionPointer stopHandler); + public abstract void registerStopHandler(BFunctionPointer stopHandler); /** * Invoke a Ballerina function pointer asynchronously. diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/TypeTags.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/TypeTags.java index 9f6b2cdbb192..94882acdee29 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/TypeTags.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/TypeTags.java @@ -22,7 +22,7 @@ * * @since 0.995.0 */ -public class TypeTags { +public final class TypeTags { public static final int INT_TAG = 1; public static final int BYTE_TAG = INT_TAG + 1; @@ -88,42 +88,35 @@ public class TypeTags { public static final int REG_EXP_TYPE_TAG = TYPE_REFERENCED_TYPE_TAG + 1; + private TypeTags() { + } + public static boolean isIntegerTypeTag(int tag) { // TODO : Fix byte type. Ideally, byte belongs to here. But we have modeled it differently. - switch (tag) { - case INT_TAG: - case SIGNED32_INT_TAG: - case SIGNED16_INT_TAG: - case SIGNED8_INT_TAG: - case UNSIGNED32_INT_TAG: - case UNSIGNED16_INT_TAG: - case UNSIGNED8_INT_TAG: - return true; - } - return false; + return switch (tag) { + case INT_TAG, + SIGNED32_INT_TAG, + SIGNED16_INT_TAG, + SIGNED8_INT_TAG, + UNSIGNED32_INT_TAG, + UNSIGNED16_INT_TAG, + UNSIGNED8_INT_TAG -> true; + default -> false; + }; } public static boolean isXMLTypeTag(int tag) { - - switch (tag) { - case XML_TAG: - case XML_ELEMENT_TAG: - case XML_COMMENT_TAG: - case XML_PI_TAG: - case XML_TEXT_TAG: - return true; - } - return false; + return switch (tag) { + case XML_TAG, XML_ELEMENT_TAG, XML_COMMENT_TAG, XML_PI_TAG, XML_TEXT_TAG -> true; + default -> false; + }; } public static boolean isStringTypeTag(int tag) { - - switch (tag) { - case STRING_TAG: - case CHAR_STRING_TAG: - return true; - } - return false; + return switch (tag) { + case STRING_TAG, CHAR_STRING_TAG -> true; + default -> false; + }; } } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/constants/RuntimeConstants.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/constants/RuntimeConstants.java index 42cd5f0f4400..9dd918efebe1 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/constants/RuntimeConstants.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/constants/RuntimeConstants.java @@ -29,7 +29,7 @@ * * @since 0.90 */ -public class RuntimeConstants { +public final class RuntimeConstants { public static final String MAIN_FUNCTION_NAME = "main"; public static final String MODULE_INIT_CLASS_NAME = "$_init"; @@ -108,14 +108,15 @@ public class RuntimeConstants { public static final BigDecimal BINT_MIN_VALUE_BIG_DECIMAL_RANGE_MIN = new BigDecimal("-9223372036854775808.5", MathContext.DECIMAL128); // runtime related error message constant values - public static final String INTERNAL_ERROR_MESSAGE = - "ballerina: Oh no, something really went wrong. Bad. Sad.\n" + - "\n" + - "We appreciate it if you can report the code that broke Ballerina in\n" + - "https://github.com/ballerina-platform/ballerina-lang/issues with the\n" + - "log you get below and your sample code.\n" + - "\n" + - "We thank you for helping make us better.\n"; + public static final String INTERNAL_ERROR_MESSAGE = """ + ballerina: Oh no, something really went wrong. Bad. Sad. + + We appreciate it if you can report the code that broke Ballerina in + https://github.com/ballerina-platform/ballerina-lang/issues with the + log you get below and your sample code. + + We thank you for helping make us better. + """; public static final String DEFAULT_LOG_FILE_HANDLER_PATTERN = "org.ballerinalang.logging.handlers.DefaultLogFileHandler.pattern"; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/constants/TypeConstants.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/constants/TypeConstants.java index 5433d38bfc6c..1ed999b25a15 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/constants/TypeConstants.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/constants/TypeConstants.java @@ -25,7 +25,7 @@ * * @since 0.995.0 */ -public class TypeConstants { +public final class TypeConstants { public static final String INT_TNAME = "int"; public static final String BYTE_TNAME = "byte"; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/creators/ErrorCreator.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/creators/ErrorCreator.java index ff212255630b..386a27c17b7d 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/creators/ErrorCreator.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/creators/ErrorCreator.java @@ -38,10 +38,13 @@ * * @since 2.0.0 */ -public class ErrorCreator { +public final class ErrorCreator { private static final BString ERROR_MESSAGE_FIELD = StringUtils.fromString("message"); + private ErrorCreator() { + } + /** * Create an error with given reason. * @@ -79,7 +82,7 @@ public static BError createError(BString message, BString details) { } else { initialValues = new MappingInitialValueEntry[0]; } - MapValueImpl detailMap = new MapValueImpl(PredefinedTypes.TYPE_ERROR_DETAIL, initialValues); + MapValueImpl detailMap = new MapValueImpl<>(PredefinedTypes.TYPE_ERROR_DETAIL, initialValues); return createError(message, detailMap); } @@ -127,7 +130,7 @@ public static BError createError(Type type, BString message, BString details) { } else { initialValues = new MappingInitialValueEntry[0]; } - MapValueImpl detailMap = new MapValueImpl(PredefinedTypes.TYPE_ERROR_DETAIL, initialValues); + MapValueImpl detailMap = new MapValueImpl<>(PredefinedTypes.TYPE_ERROR_DETAIL, initialValues); return createError(type, message, null, detailMap); } @@ -138,8 +141,8 @@ public static BError createError(Type type, BString message, BString details) { * @return new error */ public static BError createError(Throwable error) { - if (error instanceof BError) { - return (BError) error; + if (error instanceof BError bError) { + return bError; } BError bError = createError(StringUtils.fromString(error.toString())); bError.setStackTrace(error.getStackTrace()); diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/creators/TypeCreator.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/creators/TypeCreator.java index fc3b277ee195..b041914300b6 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/creators/TypeCreator.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/creators/TypeCreator.java @@ -56,7 +56,7 @@ * * @since 2.0.0 */ -public class TypeCreator { +public final class TypeCreator { /** * Creates a new array type with given element type. diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/creators/ValueCreator.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/creators/ValueCreator.java index 5629be0bd46a..2ae086cf7621 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/creators/ValueCreator.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/creators/ValueCreator.java @@ -27,6 +27,7 @@ import io.ballerina.runtime.api.types.TableType; import io.ballerina.runtime.api.types.TupleType; import io.ballerina.runtime.api.types.Type; +import io.ballerina.runtime.api.types.XmlNodeType; import io.ballerina.runtime.api.values.BArray; import io.ballerina.runtime.api.values.BDecimal; import io.ballerina.runtime.api.values.BError; @@ -69,6 +70,7 @@ import java.io.InputStream; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Function; @@ -80,7 +82,7 @@ * * @since 1.1.0 */ -public class ValueCreator { +public final class ValueCreator { /** * Creates a new array with given array type. @@ -318,8 +320,8 @@ public static BDecimal createDecimalValue(String value, DecimalValueKind valueKi * @param type {@code FunctionType} of the function pointer * @return function pointer */ - public static BFunctionPointer createFPValue(Function function, FunctionType type) { - return new FPValue(function, type, null, false); + public static BFunctionPointer createFPValue(Function function, FunctionType type) { + return new FPValue<>(function, type, null, false); } /** @@ -330,8 +332,9 @@ public static BFunctionPointer createFPValue(Function function, FunctionType typ * @param strandName name for newly creating strand which is used to run the function pointer * @return function pointer */ - public static BFunctionPointer createFPValue(Function function, FunctionType type, String strandName) { - return new FPValue(function, type, strandName, false); + public static BFunctionPointer createFPValue(Function function, + FunctionType type, String strandName) { + return new FPValue<>(function, type, strandName, false); } // TODO: remove this with https://github.com/ballerina-platform/ballerina-lang/issues/40175 @@ -578,7 +581,15 @@ public static BXmlSequence createXmlSequence(BArray sequence) { * @return xml sequence */ public static BXmlSequence createXmlSequence(List sequence) { - return XmlFactory.createXmlSequence(sequence); + List flattenedSequence = new ArrayList<>(); + for (BXml item : sequence) { + if (item.getNodeType() == XmlNodeType.SEQUENCE) { + flattenedSequence.addAll(((XmlSequence) item).getChildrenList()); + } else { + flattenedSequence.add(item); + } + } + return XmlFactory.createXmlSequence(flattenedSequence); } /** @@ -776,7 +787,7 @@ public static BMapInitialValueEntry createKeyFieldEntry(Object key, Object value * @param mappingValue mapping value * @return spread field entry */ - public static BMapInitialValueEntry createSpreadFieldEntry(BMap mappingValue) { + public static BMapInitialValueEntry createSpreadFieldEntry(BMap mappingValue) { return new MappingInitialValueEntry.SpreadFieldEntry(mappingValue); } @@ -947,8 +958,8 @@ public static BHandle createHandleValue(Object value) { * @param tableType table type * @return table value for given type */ - public static BTable createTableValue(TableType tableType) { - return new TableValueImpl(tableType); + public static BTable createTableValue(TableType tableType) { + return new TableValueImpl<>(tableType); } /** @@ -959,8 +970,8 @@ public static BTable createTableValue(TableType tableType) { * @param fieldNames table field names * @return table value for given type */ - public static BTable createTableValue(TableType tableType, BArray data, BArray fieldNames) { - return new TableValueImpl(tableType, (ArrayValue) data, (ArrayValue) fieldNames); + public static BTable createTableValue(TableType tableType, BArray data, BArray fieldNames) { + return new TableValueImpl<>(tableType, (ArrayValue) data, (ArrayValue) fieldNames); } private ValueCreator() { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/flags/SymbolFlags.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/flags/SymbolFlags.java index 1f27d428c906..edf7cee02f93 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/flags/SymbolFlags.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/flags/SymbolFlags.java @@ -22,7 +22,7 @@ * * @since 0.95.7 */ -public class SymbolFlags { +public final class SymbolFlags { public static final long PUBLIC = 1; public static final long NATIVE = 2; @@ -42,6 +42,9 @@ public class SymbolFlags { public static final long ENUM = 8589934592L; public static final long ANY_FUNCTION = 549755813888L; + private SymbolFlags() { + } + public static boolean isFlagOn(long bitmask, long flag) { return (bitmask & flag) == flag; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/flags/TypeFlags.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/flags/TypeFlags.java index a5902852f010..2b9822daf21d 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/flags/TypeFlags.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/flags/TypeFlags.java @@ -22,12 +22,15 @@ * * @since 1.1.0 */ -public class TypeFlags { +public final class TypeFlags { public static final int NILABLE = 1; public static final int ANYDATA = NILABLE << 1; public static final int PURETYPE = ANYDATA << 1; + private TypeFlags() { + } + public static boolean isFlagOn(int bitmask, int flag) { return (bitmask & flag) == flag; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/ArrayType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/ArrayType.java index f4b10a88da06..b7d3c32f0e84 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/ArrayType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/ArrayType.java @@ -48,7 +48,7 @@ enum ArrayState { INFERRED((byte) 2), OPEN((byte) 3); - byte value; + final byte value; ArrayState(byte value) { this.value = value; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/FunctionType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/FunctionType.java index 31795cd7d126..94410bea3242 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/FunctionType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/FunctionType.java @@ -32,6 +32,7 @@ public interface FunctionType extends AnnotatableType { Type getReturnType(); + @Override long getFlags(); Type getReturnParameterType(); diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/Parameter.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/Parameter.java index a438db0b6057..3a93275de3cd 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/Parameter.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/Parameter.java @@ -42,11 +42,10 @@ public boolean equals(Object o) { return true; } - if (!(o instanceof Parameter)) { + if (!(o instanceof Parameter that)) { return false; } - Parameter that = (Parameter) o; return this.name.equals(that.name) && this.type.equals(that.type) && this.isDefault == that.isDefault; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/RemoteMethodType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/RemoteMethodType.java index cd0aeff2ff44..7f1e6970cbba 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/RemoteMethodType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/RemoteMethodType.java @@ -24,8 +24,10 @@ */ public interface RemoteMethodType extends MethodType { + @Override ObjectType getParentObjectType(); + @Override FunctionType getType(); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/SelectivelyImmutableReferenceType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/SelectivelyImmutableReferenceType.java index 06a023b55385..d6ee14541391 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/SelectivelyImmutableReferenceType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/SelectivelyImmutableReferenceType.java @@ -25,7 +25,9 @@ */ public interface SelectivelyImmutableReferenceType extends IntersectableReferenceType { + @Override IntersectionType getImmutableType(); + @Override void setImmutableType(IntersectionType immutableType); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/StructureType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/StructureType.java index 7ed99c5a3f7d..8e1ba25b797a 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/StructureType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/StructureType.java @@ -30,5 +30,6 @@ public interface StructureType extends AnnotatableType { Map getFields(); + @Override long getFlags(); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/UnionType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/UnionType.java index 000b727e56f5..efb7e21afb4c 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/UnionType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/UnionType.java @@ -32,5 +32,6 @@ public interface UnionType extends SelectivelyImmutableReferenceType { boolean isCyclic(); + @Override long getFlags(); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/XmlNodeType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/XmlNodeType.java index d40536c02ac1..3dddae0727ab 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/XmlNodeType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/types/XmlNodeType.java @@ -30,7 +30,7 @@ public enum XmlNodeType { COMMENT("comment"), PI("pi"); - String nodeType; + final String nodeType; XmlNodeType(String value) { nodeType = value; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/IdentifierUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/IdentifierUtils.java index edbc873f7082..e5bdf708122f 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/IdentifierUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/IdentifierUtils.java @@ -25,7 +25,7 @@ * * @since 2.0.0 */ -public class IdentifierUtils { +public final class IdentifierUtils { private IdentifierUtils() { } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/JsonUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/JsonUtils.java index e943cfaa4097..e0f6b1d6ed55 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/JsonUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/JsonUtils.java @@ -21,7 +21,6 @@ import io.ballerina.runtime.api.TypeTags; import io.ballerina.runtime.api.creators.TypeCreator; import io.ballerina.runtime.api.creators.ValueCreator; -import io.ballerina.runtime.api.types.ArrayType; import io.ballerina.runtime.api.types.JsonType; import io.ballerina.runtime.api.types.MapType; import io.ballerina.runtime.api.types.StructureType; @@ -64,7 +63,10 @@ * * @since 2.0.0 */ -public class JsonUtils { +public final class JsonUtils { + + private JsonUtils() { + } /** * Parses the contents in the given {@link InputStream} and returns a json. @@ -153,7 +155,7 @@ public static Object parse(Reader reader, NonStringValueProcessingMode mode) thr * @param bTable {@link BTable} to be converted to JSON * @return JSON representation of the provided bTable */ - public static Object parse(BTable bTable) { + public static Object parse(BTable bTable) { return JsonInternalUtils.toJSON(bTable); } @@ -339,10 +341,10 @@ private static Object getJsonObject(Object value, List unresolved newValue = convertArrayToJson((BArray) value, unresolvedValues); break; case TypeTags.TABLE_TAG: - BTable bTable = (BTable) value; + BTable bTable = (BTable) value; Type constrainedType = TypeUtils.getImpliedType(((TableType) sourceType).getConstrainedType()); if (constrainedType.getTag() == TypeTags.MAP_TAG) { - newValue = convertMapConstrainedTableToJson((BTable) value, unresolvedValues); + newValue = convertMapConstrainedTableToJson((BTable) value, unresolvedValues); } else { try { newValue = JsonInternalUtils.toJSON(bTable); @@ -362,12 +364,12 @@ private static Object getJsonObject(Object value, List unresolved return newValue; } - private static Object convertMapConstrainedTableToJson(BTable value, List unresolvedValues) { + private static Object convertMapConstrainedTableToJson(BTable value, List unresolvedValues) { BArray membersArray = ValueCreator.createArrayValue(PredefinedTypes.TYPE_JSON_ARRAY); - BIterator itr = value.getIterator(); + BIterator itr = value.getIterator(); while (itr.hasNext()) { BArray tupleValue = (BArray) itr.next(); - BMap mapValue = ((BMap) tupleValue.get(0)); + BMap mapValue = ((BMap) tupleValue.get(0)); Object member = convertMapToJson(mapValue, unresolvedValues); membersArray.append(member); } @@ -377,7 +379,7 @@ private static Object convertMapConstrainedTableToJson(BTable value, List map, List unresolvedValues) { BMap newMap = ValueCreator.createMapValue(TypeCreator.createMapType(PredefinedTypes.TYPE_JSON)); - for (Map.Entry entry : map.entrySet()) { + for (Map.Entry entry : map.entrySet()) { Object newValue = convertToJsonType(entry.getValue(), unresolvedValues); newMap.put(StringUtils.fromString(entry.getKey().toString()), newValue); } @@ -385,7 +387,7 @@ private static Object convertMapToJson(BMap map, List unres } private static Object convertArrayToJson(BArray array, List unresolvedValues) { - BArray newArray = ValueCreator.createArrayValue((ArrayType) PredefinedTypes.TYPE_JSON_ARRAY); + BArray newArray = ValueCreator.createArrayValue(PredefinedTypes.TYPE_JSON_ARRAY); for (int i = 0; i < array.size(); i++) { Object newValue = convertToJsonType(array.get(i), unresolvedValues); newArray.add(i, newValue); diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/StringUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/StringUtils.java index 09f701755ab1..44e6f75ab783 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/StringUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/StringUtils.java @@ -57,7 +57,7 @@ * * @since 0.95.3 */ -public class StringUtils { +public final class StringUtils { /** * Convert input stream to String. @@ -237,20 +237,19 @@ public static String getJsonString(Object value) { Object jsonValue = JsonUtils.convertToJson(value); Type type = TypeUtils.getImpliedType(TypeChecker.getType(jsonValue)); - switch (type.getTag()) { - case TypeTags.NULL_TAG: - return "null"; - case TypeTags.STRING_TAG: - return stringToJson((BString) jsonValue); - case TypeTags.MAP_TAG: - MapValueImpl mapValue = (MapValueImpl) jsonValue; - return mapValue.getJSONString(); - case TypeTags.ARRAY_TAG: + return switch (type.getTag()) { + case TypeTags.NULL_TAG -> "null"; + case TypeTags.STRING_TAG -> stringToJson((BString) jsonValue); + case TypeTags.MAP_TAG -> { + MapValueImpl mapValue = (MapValueImpl) jsonValue; + yield mapValue.getJSONString(); + } + case TypeTags.ARRAY_TAG -> { ArrayValue arrayValue = (ArrayValue) jsonValue; - return arrayValue.getJSONString(); - default: - return String.valueOf(jsonValue); - } + yield arrayValue.getJSONString(); + } + default -> String.valueOf(jsonValue); + }; } private static String stringToJson(BString value) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/TypeUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/TypeUtils.java index 731b73b35e2d..71fc7f2c8a9d 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/TypeUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/TypeUtils.java @@ -50,75 +50,54 @@ * * @since 2.0.0 */ -public class TypeUtils { +public final class TypeUtils { private TypeUtils() { } public static boolean isValueType(Type type) { Type referredType = TypeUtils.getImpliedType(type); - switch (referredType.getTag()) { - case TypeTags.INT_TAG: - case TypeTags.BYTE_TAG: - case TypeTags.FLOAT_TAG: - case TypeTags.DECIMAL_TAG: - case TypeTags.BOOLEAN_TAG: - case TypeTags.STRING_TAG: - return true; - case TypeTags.FINITE_TYPE_TAG: + return switch (referredType.getTag()) { + case TypeTags.INT_TAG, + TypeTags.BYTE_TAG, + TypeTags.FLOAT_TAG, + TypeTags.DECIMAL_TAG, + TypeTags.BOOLEAN_TAG, + TypeTags.STRING_TAG -> true; + case TypeTags.FINITE_TYPE_TAG -> { for (Object value : ((BFiniteType) referredType).valueSpace) { if (!isValueType(TypeChecker.getType(value))) { - return false; + yield false; } } - return true; - default: - return false; - - } + yield true; + } + default -> false; + }; } public static Type getTypeFromName(String typeName) { - switch (typeName) { - case TypeConstants.INT_TNAME: - return TYPE_INT; - case TypeConstants.BYTE_TNAME: - return TYPE_BYTE; - case TypeConstants.FLOAT_TNAME: - return TYPE_FLOAT; - case TypeConstants.DECIMAL_TNAME: - return TYPE_DECIMAL; - case TypeConstants.STRING_TNAME: - return TYPE_STRING; - case TypeConstants.BOOLEAN_TNAME: - return TYPE_BOOLEAN; - case TypeConstants.JSON_TNAME: - return TYPE_JSON; - case TypeConstants.XML_TNAME: - return TYPE_XML; - case TypeConstants.MAP_TNAME: - return TYPE_MAP; - case TypeConstants.FUTURE_TNAME: - return TYPE_FUTURE; - case TypeConstants.STREAM_TNAME: - return TYPE_STREAM; - case TypeConstants.ANY_TNAME: - return TYPE_ANY; - case TypeConstants.TYPEDESC_TNAME: - return TYPE_TYPEDESC; - case TypeConstants.NULL_TNAME: - return TYPE_NULL; - case TypeConstants.XML_ATTRIBUTES_TNAME: - return TYPE_XML_ATTRIBUTES; - case TypeConstants.ERROR: - return TYPE_ERROR; - case TypeConstants.ANYDATA_TNAME: - return TYPE_ANYDATA; - case TypeConstants.NEVER_TNAME: - return TYPE_NEVER; - default: - throw new IllegalStateException("Unknown type name"); - } + return switch (typeName) { + case TypeConstants.INT_TNAME -> TYPE_INT; + case TypeConstants.BYTE_TNAME -> TYPE_BYTE; + case TypeConstants.FLOAT_TNAME -> TYPE_FLOAT; + case TypeConstants.DECIMAL_TNAME -> TYPE_DECIMAL; + case TypeConstants.STRING_TNAME -> TYPE_STRING; + case TypeConstants.BOOLEAN_TNAME -> TYPE_BOOLEAN; + case TypeConstants.JSON_TNAME -> TYPE_JSON; + case TypeConstants.XML_TNAME -> TYPE_XML; + case TypeConstants.MAP_TNAME -> TYPE_MAP; + case TypeConstants.FUTURE_TNAME -> TYPE_FUTURE; + case TypeConstants.STREAM_TNAME -> TYPE_STREAM; + case TypeConstants.ANY_TNAME -> TYPE_ANY; + case TypeConstants.TYPEDESC_TNAME -> TYPE_TYPEDESC; + case TypeConstants.NULL_TNAME -> TYPE_NULL; + case TypeConstants.XML_ATTRIBUTES_TNAME -> TYPE_XML_ATTRIBUTES; + case TypeConstants.ERROR -> TYPE_ERROR; + case TypeConstants.ANYDATA_TNAME -> TYPE_ANYDATA; + case TypeConstants.NEVER_TNAME -> TYPE_NEVER; + default -> throw new IllegalStateException("Unknown type name"); + }; } public static Type fromString(String typeName) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/ValueUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/ValueUtils.java index 0728d1460d9b..b5c1cc3f2cd2 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/ValueUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/ValueUtils.java @@ -31,7 +31,7 @@ * * @since 2201.5.0 */ -public class ValueUtils { +public final class ValueUtils { private ValueUtils() {} diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/XmlUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/XmlUtils.java index ea7731763dd4..3f65db5552a8 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/XmlUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/utils/XmlUtils.java @@ -34,7 +34,7 @@ * * @since 2.0.0 */ -public class XmlUtils { +public final class XmlUtils { private XmlUtils() {} @@ -95,8 +95,8 @@ public static BXml parse(Reader reader) { * @param table {@link BTable} to convert * @return converted {@link BXml} */ - public static BXml parse(BTable table) { - return XmlFactory.tableToXML((TableValueImpl) table); + public static BXml parse(BTable table) { + return XmlFactory.tableToXML((TableValueImpl) table); } /** diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BDecimal.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BDecimal.java index ab8243822b75..c50eb32f9cb9 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BDecimal.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BDecimal.java @@ -102,8 +102,8 @@ public interface BDecimal { BDecimal subtract(BDecimal subtrahend); /** - * Returns a decimal whose value is (this × - * multiplicand). + * Returns a decimal whose value is {@code (this × + * multiplicand)}. * * @param multiplicand value to be multiplied * @return value after multiplication diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BError.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BError.java index 624bafab869e..88b368d827f4 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BError.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BError.java @@ -56,6 +56,7 @@ public BError(BString message) { * * @return error cause */ + @Override public abstract BError getCause(); /** @@ -63,6 +64,7 @@ public BError(BString message) { * * @param printWriter {@code PrintWriter} to be used */ + @Override public void printStackTrace(PrintWriter printWriter) { printWriter.print(ERROR_PRINT_PREFIX + getPrintableStackTrace()); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BFuture.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BFuture.java index 4dd5a683febd..4997c9b9d61e 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BFuture.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BFuture.java @@ -1,75 +1,75 @@ - /* - * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. 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.runtime.api.values; +/* + * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.runtime.api.values; - import io.ballerina.runtime.api.async.Callback; - import io.ballerina.runtime.internal.scheduling.Strand; +import io.ballerina.runtime.api.async.Callback; +import io.ballerina.runtime.internal.scheduling.Strand; - /** - *

- * Represent a Ballerina future in Java. - *

- * - * @since 1.1.0 - */ - public interface BFuture extends BValue { +/** + *

+ * Represent a Ballerina future in Java. + *

+ * + * @since 1.1.0 + */ +public interface BFuture extends BValue { - /** - * Abort execution of the Ballerina strand that the future is attached. - * The abortion occurs only after the next yield point. - */ - void cancel(); + /** + * Abort execution of the Ballerina strand that the future is attached. + * The abortion occurs only after the next yield point. + */ + void cancel(); - // TODO: remove this with https://github.com/ballerina-platform/ballerina-lang/issues/40175 - /** - * Returns the strand that the future is attached to. - * - * @return strand - * @deprecated - */ - @Deprecated(since = "2201.6.0", forRemoval = true) - Strand getStrand(); + // TODO: remove this with https://github.com/ballerina-platform/ballerina-lang/issues/40175 + /** + * Returns the strand that the future is attached to. + * + * @return strand + * @deprecated + */ + @Deprecated(since = "2201.6.0", forRemoval = true) + Strand getStrand(); - /** - * Returns the result value of the future. - * - * @return result value - */ - Object getResult(); + /** + * Returns the result value of the future. + * + * @return result value + */ + Object getResult(); - /** - * Returns completion status of the Ballerina strand that the future is attached. - * - * @return true if future is completed - */ - boolean isDone(); + /** + * Returns completion status of the Ballerina strand that the future is attached. + * + * @return true if future is completed + */ + boolean isDone(); - /** - * Returns {@code Throwable} if the attached strand panic. - * - * @return panic error or null if not panic occurred - */ - Throwable getPanic(); + /** + * Returns {@code Throwable} if the attached strand panic. + * + * @return panic error or null if not panic occurred + */ + Throwable getPanic(); - /** - * Returns {@link Callback} listening on the completion of this future. - * - * @return registered {@link Callback} - */ - Callback getCallback(); - } + /** + * Returns {@link Callback} listening on the completion of this future. + * + * @return registered {@link Callback} + */ + Callback getCallback(); +} diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BMap.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BMap.java index 09d06c3c674d..1eb65cc3fab8 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BMap.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BMap.java @@ -54,43 +54,43 @@ public interface BMap extends BRefValue, BCollection { /** * Associates the specified value with the specified key in this map (optional operation). If the map * previously contained a mapping for the key, the old value is replaced by the specified value. (A map - * m is said to contain a mapping for a key k if and only if {@link #containsKey(Object) - * m.containsKey(k)} would return true.) + * {@code m} is said to contain a mapping for a key {@code k} if and only if {@link #containsKey(Object) + * m.containsKey(k)} would return {@code true}.) * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key - * @return the previous value associated with key, or null if there was no mapping for - * key. (A null return can also indicate that the map previously associated - * null with key, if the implementation supports null values.) + * @return the previous value associated with {@code key}, or {@code null} if there was no mapping for + * {@code key}. (A {@code null} return can also indicate that the map previously associated + * {@code null} with {@code key}, if the implementation supports {@code null} values.) */ V put(K key, V value); /** * Removes the mapping for a key from this map if it is present (optional operation). Returns the value - * to which this map previously associated the key, or null if the map contained no mapping for + * to which this map previously associated the key, or {@code null} if the map contained no mapping for * the key. * *

- * If this map permits null values, then a return value of null does not necessarily + * If this map permits null values, then a return value of {@code null} does not necessarily * indicate that the map contained no mapping for the key; it's also possible that the map explicitly - * mapped the key to null. + * mapped the key to {@code null}. * *

* The map will not contain a mapping for the specified key once the * call returns. * * @param key key whose mapping is to be removed from the map - * @return the previous value associated with key, or null if there was no mapping for - * key. + * @return the previous value associated with {@code key}, or {@code null} if there was no mapping for + * {@code key}. */ V remove(Object key); /** - * Returns true if this map contains a mapping for the specified + * Returns {@code true} if this map contains a mapping for the specified * key. * * @param key key whose presence in this map is to be tested - * @return true if this map contains a mapping for the specified key + * @return {@code true} if this map contains a mapping for the specified key */ boolean containsKey(Object key); @@ -146,12 +146,13 @@ public interface BMap extends BRefValue, BCollection { * * @return the number of key-value mappings in this map */ + @Override int size(); /** - * Returns true if this map contains no key-value mappings. + * Returns {@code true} if this map contains no key-value mappings. * - * @return true if this map contains no key-value mappings + * @return {@code true} if this map contains no key-value mappings */ boolean isEmpty(); @@ -189,7 +190,7 @@ public interface BMap extends BRefValue, BCollection { long getDefaultableIntValue(BString key); - Object merge(BMap v2, boolean checkMergeability); + Object merge(BMap v2, boolean checkMergeability); void populateInitialValue(K key, V value); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BObject.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BObject.java index 1c4ab38c473d..09720948fe33 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BObject.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BObject.java @@ -48,6 +48,7 @@ public interface BObject extends BRefValue { * @deprecated use {@link BObject#getOriginalType()} ()} instead. * The API {@link BValue#getType()} should be used after fixing the issue #39850. */ + @Override @Deprecated ObjectType getType(); @@ -65,6 +66,7 @@ default Type getOriginalType() { boolean getBooleanValue(BString fieldName); + @SuppressWarnings("rawtypes") BMap getMapValue(BString fieldName); BObject getObjectValue(BString fieldName); diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BRefValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BRefValue.java index 4136a965211b..72743c9136bb 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BRefValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BRefValue.java @@ -41,6 +41,7 @@ public interface BRefValue extends BValue { * * @return A new copy of the value */ + @Override Object copy(Map refs); /** @@ -51,6 +52,7 @@ public interface BRefValue extends BValue { * * @return A new copy of the value */ + @Override Object frozenCopy(Map refs); /** diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BString.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BString.java index 4450cda817ca..b7308732d7bc 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BString.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BString.java @@ -38,6 +38,6 @@ public interface BString { BString substring(int beginIndex, int endIndex); - BIterator getIterator(); + BIterator getIterator(); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BTable.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BTable.java index 7305142f5f53..6e271ca0a5c6 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BTable.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BTable.java @@ -54,43 +54,43 @@ public interface BTable extends BRefValue, BCollection { /** * Associates the specified value with the specified key in this map (optional operation). If the map * previously contained a mapping for the key, the old value is replaced by the specified value. (A map - * m is said to contain a mapping for a key k if and only if {@link #containsKey(Object) - * m.containsKey(k)} would return true.) + * {@code m} is said to contain a mapping for a key {@code k} if and only if {@link #containsKey(Object) + * m.containsKey(k)} would return {@code true}.) * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key - * @return the previous value associated with key, or null if there was no mapping for - * key. (A null return can also indicate that the map previously associated - * null with key, if the implementation supports null values.) + * @return the previous value associated with {@code key}, or {@code null} if there was no mapping for + * {@code key}. (A {@code null} return can also indicate that the map previously associated + * {@code null} with {@code key}, if the implementation supports {@code null} values.) */ V put(K key, V value); /** * Removes the mapping for a key from this map if it is present (optional operation). Returns the value - * to which this map previously associated the key, or null if the map contained no mapping for + * to which this map previously associated the key, or {@code null} if the map contained no mapping for * the key. * *

- * If this map permits null values, then a return value of null does not necessarily + * If this map permits null values, then a return value of {@code null} does not necessarily * indicate that the map contained no mapping for the key; it's also possible that the map explicitly - * mapped the key to null. + * mapped the key to {@code null}. * *

* The map will not contain a mapping for the specified key once the * call returns. * * @param key key whose mapping is to be removed from the map - * @return the previous value associated with key, or null if there was no mapping for - * key. + * @return the previous value associated with {@code key}, or {@code null} if there was no mapping for + * {@code key}. */ V remove(Object key); /** - * Returns true if this map contains a mapping for the specified + * Returns {@code true} if this map contains a mapping for the specified * key. * * @param key key whose presence in this map is to be tested - * @return true if this map contains a mapping for the specified key + * @return {@code true} if this map contains a mapping for the specified key */ boolean containsKey(Object key); @@ -146,12 +146,13 @@ public interface BTable extends BRefValue, BCollection { * * @return the number of key-value mappings in this map */ + @Override int size(); /** - * Returns true if this map contains no key-value mappings. + * Returns {@code true} if this map contains no key-value mappings. * - * @return true if this map contains no key-value mappings + * @return {@code true} if this map contains no key-value mappings */ boolean isEmpty(); diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BXml.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BXml.java index 3131d7971917..74a434d40f0a 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BXml.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/api/values/BXml.java @@ -267,6 +267,7 @@ public interface BXml extends BRefValue, BCollection { * * @return length of this XML sequence. */ + @Override int size(); /** diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/AnnotationUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/AnnotationUtils.java index 2615a721150d..78e81eb271b1 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/AnnotationUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/AnnotationUtils.java @@ -23,6 +23,7 @@ import io.ballerina.runtime.api.types.ResourceMethodType; import io.ballerina.runtime.api.types.Type; import io.ballerina.runtime.api.utils.StringUtils; +import io.ballerina.runtime.api.utils.TypeUtils; import io.ballerina.runtime.api.values.BString; import io.ballerina.runtime.internal.scheduling.Strand; import io.ballerina.runtime.internal.types.BAnnotatableType; @@ -38,7 +39,10 @@ * * @since 0.995.0 */ -public class AnnotationUtils { +public final class AnnotationUtils { + + private AnnotationUtils() { + } /** * Method to retrieve annotations of the type from the global annotation map and set it to the type. @@ -46,19 +50,23 @@ public class AnnotationUtils { * @param globalAnnotMap The global annotation map * @param bType The type for which annotations need to be set */ - public static void processAnnotations(MapValue globalAnnotMap, Type bType) { - if (!(bType instanceof BAnnotatableType)) { + public static void processAnnotations(MapValue globalAnnotMap, Type bType) { + if (!(bType instanceof BAnnotatableType type)) { return; } - BAnnotatableType type = (BAnnotatableType) bType; - BString annotationKey = StringUtils.fromString(type.getAnnotationKey()); if (globalAnnotMap.containsKey(annotationKey)) { type.setAnnotations((MapValue) globalAnnotMap.get(annotationKey)); } - if (type.getTag() != TypeTags.OBJECT_TYPE_TAG && type.getTag() != TypeTags.SERVICE_TAG) { + if (type.getTag() == TypeTags.TYPE_REFERENCED_TYPE_TAG) { + Type impliedType = TypeUtils.getImpliedType(type); + if (isNonObjectType(impliedType.getTag())) { + return; + } + type = (BAnnotatableType) impliedType; + } else if (isNonObjectType(type.getTag())) { return; } BObjectType objectType = (BObjectType) type; @@ -75,6 +83,10 @@ public static void processAnnotations(MapValue globalAnnotMap, Type bType) { } } + private static boolean isNonObjectType(int impliedTypeTag) { + return impliedTypeTag != TypeTags.OBJECT_TYPE_TAG && impliedTypeTag != TypeTags.SERVICE_TAG; + } + private static void setMethodAnnotations(MapValue globalAnnotMap, BString annotationKey, BMethodType resourceMethod) { if (globalAnnotMap.containsKey(annotationKey)) { @@ -82,33 +94,34 @@ private static void setMethodAnnotations(MapValue globalAnnotMa } } - public static void processObjectCtorAnnotations(BObjectType bType, MapValue globalAnnotMap, Strand strand) { + public static void processObjectCtorAnnotations(BObjectType bType, + MapValue globalAnnotMap, Strand strand) { BString annotationKey = StringUtils.fromString(bType.getAnnotationKey()); if (globalAnnotMap.containsKey(annotationKey)) { Object annot = globalAnnotMap.get(annotationKey); // If annotations are already set via desugard service-decl, skip. - Object annotValue = ((FPValue) annot).call(new Object[]{strand}); + Object annotValue = ((FPValue) annot).call(new Object[]{strand}); bType.setAnnotations((MapValue) annotValue); } for (MethodType attachedFunction : bType.getMethods()) { processObjectMethodLambdaAnnotation(globalAnnotMap, strand, attachedFunction); } - if (bType instanceof BServiceType) { - var serviceType = (BServiceType) bType; - for (var resourceFunction : serviceType.getResourceMethods()) { + if (bType instanceof BServiceType serviceType) { + for (ResourceMethodType resourceFunction : serviceType.getResourceMethods()) { processObjectMethodLambdaAnnotation(globalAnnotMap, strand, resourceFunction); } } } - private static void processObjectMethodLambdaAnnotation(MapValue globalAnnotMap, Strand strand, + private static void processObjectMethodLambdaAnnotation(MapValue globalAnnotMap, Strand strand, MethodType attachedFunction) { BString annotationKey = StringUtils.fromString(attachedFunction.getAnnotationKey()); if (globalAnnotMap.containsKey(annotationKey)) { ((BMethodType) attachedFunction) - .setAnnotations((MapValue) ((FPValue) globalAnnotMap.get(annotationKey)) + .setAnnotations( + (MapValue) ((FPValue) globalAnnotMap.get(annotationKey)) .call(new Object[]{strand})); } } @@ -120,7 +133,8 @@ private static void processObjectMethodLambdaAnnotation(MapValue globalAnnotMap, * @param globalAnnotMap The global annotation map * @param name The function name that acts as the annotation key */ - public static void processFPValueAnnotations(FPValue fpValue, MapValue globalAnnotMap, String name) { + public static void processFPValueAnnotations(FPValue fpValue, + MapValue globalAnnotMap, String name) { BAnnotatableType type = (BAnnotatableType) fpValue.getType(); BString nameKey = StringUtils.fromString(name); if (globalAnnotMap.containsKey(nameKey)) { @@ -134,7 +148,7 @@ public static void processFPValueAnnotations(FPValue fpValue, MapValue globalAnn * @param fpValue function pointer to be invoked * @return true if should run concurrently */ - public static boolean isConcurrent(FPValue fpValue) { + public static boolean isConcurrent(FPValue fpValue) { return fpValue.isConcurrent; } @@ -145,7 +159,7 @@ public static boolean isConcurrent(FPValue fpValue) { * @param defaultName default strand name * @return annotated strand name */ - public static String getStrandName(FPValue fpValue, String defaultName) { + public static String getStrandName(FPValue fpValue, String defaultName) { if (fpValue.strandName != null) { return fpValue.strandName; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BLock.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BLock.java index 0541f4ea7a7e..b717de1bfeeb 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BLock.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BLock.java @@ -29,9 +29,9 @@ */ public class BLock { - private ArrayDeque current; + private final ArrayDeque current; - private ArrayDeque waitingForLock; + private final ArrayDeque waitingForLock; public BLock() { this.current = new ArrayDeque<>(); diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BLockStore.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BLockStore.java index e6b97bc11660..15ef82e435b3 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BLockStore.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BLockStore.java @@ -34,7 +34,7 @@ public class BLockStore { /** * The map of locks inferred. */ - private Map globalLockMap; + private final Map globalLockMap; public BLockStore() { globalLockMap = new ConcurrentHashMap<>(); @@ -45,9 +45,7 @@ public void addLockToMap(String lockName) { } public BLock getLockFromMap(String lockName) { - return globalLockMap.computeIfAbsent(lockName, (k) -> { - return new BLock(); - }); + return globalLockMap.computeIfAbsent(lockName, (k) -> new BLock()); } public void panicIfInLock(Strand strand) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BalEnvironment.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BalEnvironment.java index f198c9fd6dd9..6827567e2064 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BalEnvironment.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BalEnvironment.java @@ -66,6 +66,7 @@ public BalEnvironment(Strand strand, Module currentModule, String funcName, Para * * @return function name */ + @Override public String getFunctionName() { return funcName; } @@ -75,6 +76,7 @@ public String getFunctionName() { * * @return array of {@link Parameter} */ + @Override public Parameter[] getFunctionPathParameters() { return funcPathParams; } @@ -87,6 +89,7 @@ public Parameter[] getFunctionPathParameters() { * * @return BalFuture which will resume the current strand when completed. */ + @Override public BalFuture markAsync() { strand.blockedOnExtern = true; strand.setState(State.BLOCK_AND_YIELD); @@ -98,6 +101,7 @@ public BalFuture markAsync() { * * @return Ballerina runtime instance. */ + @Override public BalRuntime getRuntime() { return new BalRuntime(strand.scheduler, currentModule); } @@ -107,6 +111,7 @@ public BalRuntime getRuntime() { * * @return module of the environment. */ + @Override public Module getCurrentModule() { return currentModule; } @@ -116,6 +121,7 @@ public Module getCurrentModule() { * * @return Strand id. */ + @Override public int getStrandId() { return strand.getId(); } @@ -126,6 +132,7 @@ public int getStrandId() { * * @return Optional strand name. */ + @Override public Optional getStrandName() { return strand.getName(); } @@ -135,6 +142,7 @@ public Optional getStrandName() { * * @return metadata of the strand. */ + @Override public StrandMetadata getStrandMetadata() { return strand.getMetadata(); } @@ -145,6 +153,7 @@ public StrandMetadata getStrandMetadata() { * @param key string key * @param value value to be store in the strand */ + @Override public void setStrandLocal(String key, Object value) { strand.setProperty(key, value); } @@ -155,10 +164,12 @@ public void setStrandLocal(String key, Object value) { * @param key key * @return value stored in the strand. */ + @Override public Object getStrandLocal(String key) { return strand.getProperty(key); } + @Override public Repository getRepository() { return this.repository; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BalFuture.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BalFuture.java index 518b0fe5c361..aa9dd15ef414 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BalFuture.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BalFuture.java @@ -40,6 +40,7 @@ public BalFuture(Strand strand) { this.strand = strand; } + @Override public void complete(Object returnValue) { if (visited.getAndSet(true)) { throw ErrorCreator.createError(StringUtils.fromString("cannot complete the same future twice."), diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BalRuntime.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BalRuntime.java index 63d18add5b87..e721fbc45b07 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BalRuntime.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BalRuntime.java @@ -38,9 +38,10 @@ import io.ballerina.runtime.internal.errors.ErrorHelper; import io.ballerina.runtime.internal.launch.LaunchUtils; import io.ballerina.runtime.internal.scheduling.AsyncUtils; +import io.ballerina.runtime.internal.scheduling.RuntimeRegistry; import io.ballerina.runtime.internal.scheduling.Scheduler; import io.ballerina.runtime.internal.scheduling.Strand; -import io.ballerina.runtime.internal.util.RuntimeUtils; +import io.ballerina.runtime.internal.scheduling.SyncCallback; import io.ballerina.runtime.internal.values.FutureValue; import io.ballerina.runtime.internal.values.ObjectValue; import io.ballerina.runtime.internal.values.ValueCreator; @@ -48,13 +49,16 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.file.Path; +import java.util.HashMap; import java.util.Map; +import java.util.concurrent.CountDownLatch; import java.util.function.Function; import static io.ballerina.identifier.Utils.encodeNonFunctionIdentifier; import static io.ballerina.runtime.api.constants.RuntimeConstants.ANON_ORG; import static io.ballerina.runtime.api.constants.RuntimeConstants.CONFIGURATION_CLASS_NAME; import static io.ballerina.runtime.api.constants.RuntimeConstants.DOT; +import static io.ballerina.runtime.api.constants.RuntimeConstants.MODULE_INIT_CLASS_NAME; /** * Internal implementation of the API used by the interop users to control Ballerina runtime behavior. @@ -66,6 +70,9 @@ public class BalRuntime extends Runtime { private final Scheduler scheduler; private final Module module; private boolean moduleInitialized = false; + private boolean moduleStarted = false; + private boolean moduleStopped = false; + private Thread schedulerThread = null; public BalRuntime(Scheduler scheduler, Module module) { this.scheduler = scheduler; @@ -73,48 +80,68 @@ public BalRuntime(Scheduler scheduler, Module module) { } public BalRuntime(Module module) { - this.scheduler = new Scheduler(false); + this.scheduler = new Scheduler(true); this.module = module; } + @Override public void init() { - invokeConfigInit(); - invokeMethodAsync("$moduleInit", null, PredefinedTypes.TYPE_NULL, "init", new Object[1]); - moduleInitialized = true; + if (moduleInitialized) { + throw ErrorHelper.getRuntimeException(ErrorCodes.FUNCTION_ALREADY_CALLED, "init"); + } + try { + invokeConfigInit(); + schedulerThread = new Thread(scheduler::start); + schedulerThread.start(); + invokeMethodSync("$moduleInit"); + moduleInitialized = true; + } catch (ClassNotFoundException e) { + throw ErrorCreator.createError(StringUtils.fromString(String.format("module '%s' does not exist", module))); + } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) { + throw ErrorCreator.createError(StringUtils.fromString("error occurred while initializing the ballerina " + + "module due to " + e.getMessage()), e); + } } + @Override public void start() { if (!moduleInitialized) { - throw ErrorHelper.getRuntimeException(ErrorCodes.INVALID_METHOD_CALL, "start"); + throw ErrorHelper.getRuntimeException(ErrorCodes.INVALID_FUNCTION_INVOCATION_BEFORE_MODULE_INIT, "start"); + } + if (moduleStarted) { + throw ErrorHelper.getRuntimeException(ErrorCodes.FUNCTION_ALREADY_CALLED, "start"); } - invokeMethodAsync("$moduleStart", null, PredefinedTypes.TYPE_NULL, "start", new Object[1]); + invokeMethodSync("$moduleStart"); + moduleStarted = true; } + @Override public void invokeMethodAsync(String functionName, Callback callback, Object... args) { if (!moduleInitialized) { - throw ErrorHelper.getRuntimeException(ErrorCodes.INVALID_FUNCTION_INVOCATION, functionName); + throw ErrorHelper.getRuntimeException(ErrorCodes.INVALID_FUNCTION_INVOCATION_BEFORE_MODULE_INIT, + functionName); } - invokeMethodAsync(functionName, callback, PredefinedTypes.TYPE_ANY, functionName, args); + invokeMethod(functionName, callback, PredefinedTypes.TYPE_ANY, functionName, args); } + @Override public void stop() { if (!moduleInitialized) { - throw ErrorHelper.getRuntimeException(ErrorCodes.INVALID_METHOD_CALL, "stop"); + throw ErrorHelper.getRuntimeException(ErrorCodes.INVALID_FUNCTION_INVOCATION_BEFORE_MODULE_INIT, "stop"); + } + if (moduleStopped) { + throw ErrorHelper.getRuntimeException(ErrorCodes.FUNCTION_ALREADY_CALLED, "stop"); + } + try { + scheduler.poison(); + schedulerThread.join(); + invokeModuleStop(); + moduleStopped = true; + } catch (InterruptedException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException | + IllegalAccessException e) { + throw ErrorCreator.createError(StringUtils.fromString("error occurred during module stop due to " + + e.getMessage()), e); } - invokeMethodAsync("$moduleStop", null, PredefinedTypes.TYPE_NULL, "stop", new Object[1]); - } - - private void invokeMethodAsync(String functionName, Callback callback, Type returnType, String strandName, - Object... args) { - ValueCreator valueCreator = ValueCreator.getValueCreator(ValueCreator.getLookupKey(module.getOrg(), - module.getName(), module.getMajorVersion(), module.isTestPkg())); - Function func = o -> valueCreator.call((Strand) (((Object[]) o)[0]), functionName, args); - FutureValue future = scheduler.createFuture(null, callback, null, returnType, strandName, null); - Object[] argsWithStrand = new Object[args.length + 1]; - argsWithStrand[0] = future.strand; - System.arraycopy(args, 0, argsWithStrand, 1, args.length); - scheduler.schedule(argsWithStrand, func, future); - scheduler.start(); } /** @@ -136,6 +163,7 @@ private void invokeMethodAsync(String functionName, Callback callback, Type retu * This method needs to be called if object.getType().isIsolated() or * object.getType().isIsolated(methodName) returns false. */ + @Override public BFuture invokeMethodAsyncSequentially(BObject object, String methodName, String strandName, StrandMetadata metadata, Callback callback, Map properties, @@ -147,9 +175,10 @@ public BFuture invokeMethodAsyncSequentially(BObject object, String methodName, AsyncUtils.getArgsWithDefaultValues(scheduler, objectVal, methodName, new Callback() { @Override public void notifySuccess(Object result) { - Function func = getFunction((Object[]) result, objectVal, methodName); + Function func = getFunction((Object[]) result, objectVal, methodName); scheduler.scheduleToObjectGroup(new Object[1], func, future); } + @Override public void notifyFailure(BError error) { callback.notifyFailure(error); @@ -183,6 +212,7 @@ public void notifyFailure(BError error) { * This method needs to be called if both object.getType().isIsolated() and * object.getType().isIsolated(methodName) returns true. */ + @Override public BFuture invokeMethodAsyncConcurrently(BObject object, String methodName, String strandName, StrandMetadata metadata, Callback callback, Map properties, @@ -194,9 +224,10 @@ public BFuture invokeMethodAsyncConcurrently(BObject object, String methodName, AsyncUtils.getArgsWithDefaultValues(scheduler, objectVal, methodName, new Callback() { @Override public void notifySuccess(Object result) { - Function func = getFunction((Object[]) result, objectVal, methodName); + Function func = getFunction((Object[]) result, objectVal, methodName); scheduler.schedule(new Object[1], func, future); } + @Override public void notifyFailure(BError error) { callback.notifyFailure(error); @@ -236,6 +267,7 @@ public void notifyFailure(BError error) { * We can decide the object method isolation if and only if both object.getType().isIsolated() and * object.getType().isIsolated(methodName) returns true. */ + @Override @Deprecated public BFuture invokeMethodAsync(BObject object, String methodName, String strandName, StrandMetadata metadata, Callback callback, Map properties, @@ -249,13 +281,14 @@ public BFuture invokeMethodAsync(BObject object, String methodName, String stran AsyncUtils.getArgsWithDefaultValues(scheduler, objectVal, methodName, new Callback() { @Override public void notifySuccess(Object result) { - Function func = getFunction((Object[]) result, objectVal, methodName); + Function func = getFunction((Object[]) result, objectVal, methodName); if (isIsolated) { scheduler.schedule(new Object[1], func, future); } else { scheduler.scheduleToObjectGroup(new Object[1], func, future); } } + @Override public void notifyFailure(BError error) { callback.notifyFailure(error); @@ -288,6 +321,7 @@ public void notifyFailure(BError error) { * We can decide the object method isolation if both object.getType().isIsolated() and * object.getType().isIsolated(methodName) returns true. */ + @Override @Deprecated public Object invokeMethodAsync(BObject object, String methodName, String strandName, StrandMetadata metadata, Callback callback, Object... args) { @@ -304,59 +338,88 @@ private void validateArgs(BObject object, String methodName) { } } + @Override public void registerListener(BObject listener) { scheduler.getRuntimeRegistry().registerListener(listener); } + @Override public void deregisterListener(BObject listener) { scheduler.getRuntimeRegistry().deregisterListener(listener); } - public void registerStopHandler(BFunctionPointer stopHandler) { + @Override + public void registerStopHandler(BFunctionPointer stopHandler) { scheduler.getRuntimeRegistry().registerStopHandler(stopHandler); } - private Function getFunction(Object[] argsWithDefaultValues, ObjectValue objectVal, String methodName) { - Function func; + private Function getFunction(Object[] argsWithDefaultValues, + ObjectValue objectVal, String methodName) { + Function func; if (argsWithDefaultValues.length == 1) { - func = o -> objectVal.call((Strand) (((Object[]) o)[0]), methodName, argsWithDefaultValues[0]); + func = o -> objectVal.call((Strand) ((o)[0]), methodName, argsWithDefaultValues[0]); } else { - func = o -> objectVal.call((Strand) (((Object[]) o)[0]), methodName, argsWithDefaultValues); + func = o -> objectVal.call((Strand) ((o)[0]), methodName, argsWithDefaultValues); } return func; } - private void invokeConfigInit() { - String configClassName = getConfigClassName(this.module); - Class configClazz; - try { - configClazz = Class.forName(configClassName); - } catch (Throwable e) { - throw ErrorCreator.createError(StringUtils.fromString("failed to load configuration class :" + - configClassName)); - } + private void invokeConfigInit() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, + IllegalAccessException { + Class configClass = loadClass(CONFIGURATION_CLASS_NAME); ConfigDetails configDetails = LaunchUtils.getConfigurationDetails(); String funcName = Utils.encodeFunctionIdentifier("$configureInit"); - try { - final Method method = configClazz.getDeclaredMethod(funcName, String[].class, Path[].class, String.class); - method.invoke(null, new String[]{}, configDetails.paths, configDetails.configContent); - } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) { - throw ErrorCreator.createError(StringUtils.fromString("configurable initialization failed due to " + - RuntimeUtils.formatErrorMessage(e)), e); - } + Method method = configClass.getDeclaredMethod(funcName, Map.class, String[].class, Path[].class, String.class); + method.invoke(null, new HashMap<>(), new String[]{}, configDetails.paths, configDetails.configContent); + } + + private void invokeModuleStop() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, + IllegalAccessException { + Class configClass = loadClass(MODULE_INIT_CLASS_NAME); + Method method = configClass.getDeclaredMethod("$currentModuleStop", RuntimeRegistry.class); + method.invoke(null, scheduler.getRuntimeRegistry()); } - private static String getConfigClassName(Module module) { - String configClassName = CONFIGURATION_CLASS_NAME; + private Class loadClass(String className) throws ClassNotFoundException { + String name = getFullQualifiedClassName(this.module, className); + return Class.forName(name); + } + + private static String getFullQualifiedClassName(Module module, String className) { String orgName = module.getOrg(); String packageName = module.getName(); if (!DOT.equals(packageName)) { - configClassName = encodeNonFunctionIdentifier(packageName) + "." + module.getMajorVersion() + "." + - configClassName; + className = encodeNonFunctionIdentifier(packageName) + "." + module.getMajorVersion() + "." + className; } if (!ANON_ORG.equals(orgName)) { - configClassName = encodeNonFunctionIdentifier(orgName) + "." + configClassName; + className = encodeNonFunctionIdentifier(orgName) + "." + className; + } + return className; + } + + private void invokeMethodSync(String functionName) { + final CountDownLatch latch = new CountDownLatch(1); + SyncCallback callback = new SyncCallback(latch); + invokeMethod(functionName, callback, PredefinedTypes.TYPE_NULL, functionName, new Object[1]); + try { + latch.await(); + } catch (InterruptedException e) { + throw ErrorCreator.createError(e); + } + if (callback.initError != null) { + throw callback.initError; } - return configClassName; + } + + private void invokeMethod(String functionName, Callback callback, Type returnType, String strandName, + Object... args) { + ValueCreator valueCreator = ValueCreator.getValueCreator(ValueCreator.getLookupKey(module.getOrg(), + module.getName(), module.getMajorVersion(), module.isTestPkg())); + Function func = o -> valueCreator.call((Strand) (o[0]), functionName, args); + FutureValue future = scheduler.createFuture(null, callback, null, returnType, strandName, null); + Object[] argsWithStrand = new Object[args.length + 1]; + argsWithStrand[0] = future.strand; + System.arraycopy(args, 0, argsWithStrand, 1, args.length); + scheduler.schedule(argsWithStrand, func, future); } } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BalStringUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BalStringUtils.java index c637d5798f35..fb6d5c4540c6 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BalStringUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BalStringUtils.java @@ -50,7 +50,8 @@ * * @since 2.0.0 */ -public class BalStringUtils { +public final class BalStringUtils { + private static boolean hasCycles = false; private BalStringUtils() {} @@ -146,14 +147,13 @@ public static Object parseArrayExpressionStringValue(String exprValue, BLink par */ public static Object parseMapExpressionStringValue(String exprValue, BLink parent) { List list = getElements(exprValue); - MapValueImpl eleMap = new MapValueImpl(new BMapType(TYPE_ANYDATA)); + MapValueImpl eleMap = new MapValueImpl<>(new BMapType(TYPE_ANYDATA)); if (list.isEmpty()) { return eleMap; } CycleUtils.Node node = new CycleUtils.Node(eleMap, parent); Set typeSet = new HashSet<>(); - for (int i = 0; i < list.size(); i++) { - String e = list.get(i); + for (String e : list) { int colonIndex = e.indexOf(':'); int quotesCount = 0; for (int j = 0; j < e.length(); j++) { @@ -176,12 +176,12 @@ public static Object parseMapExpressionStringValue(String exprValue, BLink paren } if (typeSet.size() > 1) { BUnionType type = new BUnionType(new ArrayList<>(typeSet)); - MapValueImpl result = new MapValueImpl(new BMapType(type)); + MapValueImpl result = new MapValueImpl<>(new BMapType(type)); result.putAll(eleMap); return result; } else { Type type = typeSet.iterator().next(); - MapValueImpl result = new MapValueImpl(new BMapType(type)); + MapValueImpl result = new MapValueImpl<>(new BMapType(type)); result.putAll(eleMap); return result; } @@ -216,7 +216,7 @@ public static Object parseTableExpressionStringValue(String exprValue, BLink par MapType mapType = TypeCreator.createMapType(TYPE_ANYDATA, false); BTableType tableType; - if (keyFieldNames.size() == 0) { + if (keyFieldNames.isEmpty()) { tableType = (BTableType) TypeCreator.createTableType(mapType, false); } else { tableType = (BTableType) TypeCreator.createTableType(mapType, keys, false); @@ -302,7 +302,7 @@ public static List getElements(String exprValue) { part = new StringBuilder(); } } - if (part.length() > 0) { + if (!part.isEmpty()) { list.add(part.toString()); } return list; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BallerinaXmlSerializer.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BallerinaXmlSerializer.java index c836f4929cbb..cdce109da43a 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BallerinaXmlSerializer.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/BallerinaXmlSerializer.java @@ -27,7 +27,6 @@ import io.ballerina.runtime.internal.values.XmlText; import java.io.CharArrayWriter; -import java.io.IOException; import java.io.OutputStream; import java.util.ArrayDeque; import java.util.ArrayList; @@ -98,7 +97,7 @@ public void flush() { } @Override - public void close() throws IOException { + public void close() { try { xmlStreamWriter.close(); } catch (XMLStreamException e) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/CloneUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/CloneUtils.java index 9f2fa277ffe2..3a41e8eefb85 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/CloneUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/CloneUtils.java @@ -35,7 +35,7 @@ * * @since 1.0.0 */ -public class CloneUtils { +public final class CloneUtils { static final String NEWLINE_WITH_TABS = "\n\t\t"; static final String TWO_SPACES = " "; @@ -54,11 +54,10 @@ public static Object cloneValue(Object value) { return null; } - if (!(value instanceof BRefValue)) { + if (!(value instanceof BRefValue refValue)) { return value; } - BRefValue refValue = (BRefValue) value; return refValue.copy(new HashMap<>()); } @@ -74,11 +73,10 @@ public static Object cloneReadOnly(Object value) { return null; } - if (!(value instanceof BRefValue)) { + if (!(value instanceof BRefValue refValue)) { return value; } - BRefValue refValue = (BRefValue) value; return refValue.frozenCopy(new HashMap<>()); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/CycleUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/CycleUtils.java index 14e6ba03fb11..545f89c4efbf 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/CycleUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/CycleUtils.java @@ -40,6 +40,7 @@ public Node(Object obj, BLink parent) { this.parent = parent; } + @Override public boolean hasCyclesSoFar() { Node parent = (Node) this.parent; while (parent != null) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/ErrorUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/ErrorUtils.java index 613af41f7dc7..447cd9772637 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/ErrorUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/ErrorUtils.java @@ -42,7 +42,7 @@ * @since 2.0.0 */ -public class ErrorUtils { +public final class ErrorUtils { private static final BString ERROR_MESSAGE_FIELD = StringUtils.fromString("message"); private static final BString ERROR_CAUSE_FIELD = StringUtils.fromString("cause"); @@ -78,14 +78,14 @@ public static ErrorValue createInteropError(Throwable e) { } else { initialValues = new MappingInitialValueEntry[0]; } - BMap detailMap = new MapValueImpl(PredefinedTypes.TYPE_ERROR_DETAIL, initialValues); + BMap detailMap = new MapValueImpl<>(PredefinedTypes.TYPE_ERROR_DETAIL, initialValues); return (ErrorValue) createError(StringUtils.fromString(e.getClass().getName()), detailMap); } public static Object handleResourceError(Object returnValue) { - if (returnValue instanceof BError) { - throw (BError) returnValue; + if (returnValue instanceof BError error) { + throw error; } return returnValue; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/FloatUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/FloatUtils.java index 2f3229eed662..ac1af0ccb240 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/FloatUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/FloatUtils.java @@ -26,7 +26,10 @@ * * @since 2201.1.0 */ -public class FloatUtils { +public final class FloatUtils { + + private FloatUtils() { + } public static BString getBStringIfInfiniteOrNaN(double x) { if (Double.isInfinite(x) || Double.isNaN(x)) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/IteratorUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/IteratorUtils.java index bbf468df8f32..867b0a355c9d 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/IteratorUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/IteratorUtils.java @@ -34,7 +34,10 @@ * * @since 1.2.0 */ -public class IteratorUtils { +public final class IteratorUtils { + + private IteratorUtils() { + } /** * Returns the pure type and anydata type flags if they are available, otherwise 0. This is only used to check if diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/JsonDataSource.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/JsonDataSource.java index ad20f596d236..e43579211667 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/JsonDataSource.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/JsonDataSource.java @@ -33,7 +33,7 @@ public interface JsonDataSource { * @param gen The {@link JsonGenerator} object to write the data to * @throws IOException Error occurs while serializing */ - void serialize(JsonGenerator gen) throws IOException;; + void serialize(JsonGenerator gen) throws IOException; /** * Returns {@code true} if the data-source has more JSON elements. diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/JsonGenerator.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/JsonGenerator.java index 64e079ae3d7c..b9b11d98dad3 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/JsonGenerator.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/JsonGenerator.java @@ -46,7 +46,7 @@ public class JsonGenerator implements Closeable { private static final int DEFAULT_DEPTH = 10; - private Writer writer; + private final Writer writer; private boolean[] levelInit = new boolean[DEFAULT_DEPTH]; @@ -54,15 +54,15 @@ public class JsonGenerator implements Closeable { private boolean fieldActive; - private static boolean[] escChars = new boolean[93]; + private static final boolean[] ESC_CHARS = new boolean[93]; static { - escChars['"'] = true; - escChars['\\'] = true; - escChars['\b'] = true; - escChars['\n'] = true; - escChars['\r'] = true; - escChars['\t'] = true; + ESC_CHARS['"'] = true; + ESC_CHARS['\\'] = true; + ESC_CHARS['\b'] = true; + ESC_CHARS['\n'] = true; + ESC_CHARS['\r'] = true; + ESC_CHARS['\t'] = true; } public JsonGenerator(OutputStream out) { @@ -159,7 +159,7 @@ private void writeStringValue(String value) throws IOException { char[] chs = value.toCharArray(); for (int i = 0; i < count; i++) { ch = chs[i]; - if (ch < escChars.length && escChars[ch]) { + if (ch < ESC_CHARS.length && ESC_CHARS[ch]) { escaped = true; break; } @@ -274,6 +274,7 @@ public void flush() throws IOException { this.writer.flush(); } + @Override public void close() throws IOException { this.writer.close(); } @@ -287,8 +288,8 @@ public void serialize(Object json) throws IOException { switch (TypeUtils.getImpliedType(TypeChecker.getType(json)).getTag()) { case TypeTags.ARRAY_TAG: - if (json instanceof StreamingJsonValue) { - ((StreamingJsonValue) json).serialize(this); + if (json instanceof StreamingJsonValue streamingJsonValue) { + streamingJsonValue.serialize(this); break; } this.writeStartArray(); diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/JsonInternalUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/JsonInternalUtils.java index 8487c7254435..b2970e598c45 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/JsonInternalUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/JsonInternalUtils.java @@ -71,7 +71,7 @@ * @since 0.995.0 */ @SuppressWarnings("unchecked") -public class JsonInternalUtils { +public final class JsonInternalUtils { public static final String OBJECT = "object"; public static final String ARRAY = "array"; @@ -225,10 +225,10 @@ public static void setElement(Object json, String elementName, Object element) { * @return returns true if provided JSON is a JSON Array. */ public static boolean isJSONArray(Object json) { - if (!(json instanceof BRefValue)) { + if (!(json instanceof BRefValue refValue)) { return false; } - return TypeUtils.getImpliedType(((BRefValue) json).getType()).getTag() == TypeTags.ARRAY_TAG; + return TypeUtils.getImpliedType(refValue.getType()).getTag() == TypeTags.ARRAY_TAG; } /** @@ -238,11 +238,11 @@ public static boolean isJSONArray(Object json) { * @return returns true if provided JSON is a JSON Object. */ public static boolean isJSONObject(Object json) { - if (!(json instanceof BRefValue)) { + if (!(json instanceof BRefValue refValue)) { return false; } - Type type = TypeUtils.getImpliedType(((BRefValue) json).getType()); + Type type = TypeUtils.getImpliedType(refValue.getType()); int typeTag = type.getTag(); return typeTag == TypeTags.MAP_TAG || typeTag == TypeTags.RECORD_TYPE_TAG; } @@ -392,24 +392,20 @@ public static Object convertUnionTypeToJSON(Object source, JsonType targetType) } Type type = TypeUtils.getImpliedType(TypeChecker.getType(source)); - switch (type.getTag()) { - case TypeTags.INT_TAG: - case TypeTags.FLOAT_TAG: - case TypeTags.DECIMAL_TAG: - case TypeTags.STRING_TAG: - case TypeTags.BOOLEAN_TAG: - case TypeTags.JSON_TAG: - return source; - case TypeTags.NULL_TAG: - return null; - case TypeTags.MAP_TAG: - case TypeTags.OBJECT_TYPE_TAG: - case TypeTags.RECORD_TYPE_TAG: - return convertMapToJSON((MapValueImpl) source, targetType); - default: - throw ErrorHelper.getRuntimeException(ErrorCodes.INCOMPATIBLE_TYPE, - PredefinedTypes.TYPE_JSON, type); - } + return switch (type.getTag()) { + case TypeTags.INT_TAG, + TypeTags.FLOAT_TAG, + TypeTags.DECIMAL_TAG, + TypeTags.STRING_TAG, + TypeTags.BOOLEAN_TAG, + TypeTags.JSON_TAG -> source; + case TypeTags.NULL_TAG -> null; + case TypeTags.MAP_TAG, + TypeTags.OBJECT_TYPE_TAG, + TypeTags.RECORD_TYPE_TAG -> convertMapToJSON((MapValueImpl) source, targetType); + default -> throw ErrorHelper.getRuntimeException(ErrorCodes.INCOMPATIBLE_TYPE, + PredefinedTypes.TYPE_JSON, type); + }; } /** @@ -467,7 +463,7 @@ public static BError getErrorIfUnmergeable(Object j1, Object j2, List detailMap = new MapValueImpl(PredefinedTypes.TYPE_ERROR_DETAIL, + MapValueImpl detailMap = new MapValueImpl<>(PredefinedTypes.TYPE_ERROR_DETAIL, initialValues); return ErrorCreator.createError(ErrorReasons.MERGE_JSON_ERROR, detailMap); } @@ -507,13 +503,12 @@ public static Object mergeJson(Object j1, Object j2, boolean checkMergeability) * of the JSON array. Otherwise the method will throw a {@link BError}. */ public static ArrayValue convertJSONToBArray(Object json, BArrayType targetArrayType) { - if (!(json instanceof ArrayValue)) { + if (!(json instanceof ArrayValue jsonArray)) { throw ErrorHelper.getRuntimeException(ErrorCodes.INCOMPATIBLE_TYPE, getComplexObjectTypeName(ARRAY), getTypeName(json)); } Type targetElementType = TypeUtils.getImpliedType(targetArrayType.getElementType()); - ArrayValue jsonArray = (ArrayValue) json; switch (targetElementType.getTag()) { case TypeTags.INT_TAG: return jsonArrayToBIntArray(jsonArray); @@ -546,7 +541,7 @@ public static ArrayValue convertJSONToBArray(Object json, BArrayType targetArray * @param table {@link BTable} to be converted * @return JSON representation of the provided table */ - public static Object toJSON(BTable table) { + public static Object toJSON(BTable table) { TableJsonDataSource jsonDataSource = new TableJsonDataSource(table); return jsonDataSource.build(); } @@ -567,12 +562,12 @@ public static BError createJsonConversionError(Throwable throwable, String prefi * @return BInteger value of the JSON, if its a integer or a long JSON node. Error, otherwise. */ private static long jsonNodeToInt(Object json) { - if (!(json instanceof Long)) { + if (!(json instanceof Long l)) { throw ErrorHelper.getRuntimeException(ErrorCodes.INCOMPATIBLE_TYPE_FOR_CASTING_JSON, PredefinedTypes.TYPE_INT, getTypeName(json)); } - return (Long) json; + return l; } /** @@ -582,12 +577,12 @@ private static long jsonNodeToInt(Object json) { * @return BFloat value of the JSON, if its a double or a float JSON node. Error, otherwise. */ private static double jsonNodeToFloat(Object json) { - if (json instanceof Integer) { - return ((Integer) json).longValue(); - } else if (json instanceof Double) { - return (Double) json; - } else if (json instanceof DecimalValue) { - return ((DecimalValue) json).floatValue(); + if (json instanceof Integer i) { + return i.longValue(); + } else if (json instanceof Double d) { + return d; + } else if (json instanceof DecimalValue decimalValue) { + return decimalValue.floatValue(); } else { throw ErrorHelper.getRuntimeException(ErrorCodes.INCOMPATIBLE_TYPE_FOR_CASTING_JSON, PredefinedTypes.TYPE_FLOAT, getTypeName(json)); @@ -602,14 +597,14 @@ private static double jsonNodeToFloat(Object json) { */ private static DecimalValue jsonNodeToDecimal(Object json) { BigDecimal decimal; - if (json instanceof Integer) { - decimal = new BigDecimal(((Integer) json).longValue()); - } else if (json instanceof Double) { - decimal = BigDecimal.valueOf((Double) json); - } else if (json instanceof BigDecimal) { - decimal = (BigDecimal) json; - } else if (json instanceof DecimalValue) { - return (DecimalValue) json; + if (json instanceof Integer i) { + decimal = new BigDecimal(i.longValue()); + } else if (json instanceof Double d) { + decimal = BigDecimal.valueOf(d); + } else if (json instanceof BigDecimal bigDecimal) { + decimal = bigDecimal; + } else if (json instanceof DecimalValue decimalValue) { + return decimalValue; } else { throw ErrorHelper.getRuntimeException(ErrorCodes.INCOMPATIBLE_TYPE_FOR_CASTING_JSON, PredefinedTypes.TYPE_DECIMAL, getTypeName(json)); @@ -625,11 +620,11 @@ private static DecimalValue jsonNodeToDecimal(Object json) { * @return Boolean value of the JSON, if its a boolean node. Error, otherwise. */ private static boolean jsonNodeToBoolean(Object json) { - if (!(json instanceof Boolean)) { + if (!(json instanceof Boolean b)) { throw ErrorHelper.getRuntimeException(ErrorCodes.INCOMPATIBLE_TYPE_FOR_CASTING_JSON, PredefinedTypes.TYPE_BOOLEAN, getTypeName(json)); } - return (Boolean) json; + return b; } private static ArrayValue jsonArrayToBIntArray(ArrayValue arrayNode) { @@ -832,11 +827,10 @@ public ObjectPair(Object lhsObject, Object rhsObject) { @Override public boolean equals(Object obj) { - if (!(obj instanceof ObjectPair)) { + if (!(obj instanceof ObjectPair other)) { return false; } - ObjectPair other = (ObjectPair) obj; return this.lhsObject == other.lhsObject && this.rhsObject == other.rhsObject; } } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/JsonParser.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/JsonParser.java index c65a0e238db6..80a73363a64d 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/JsonParser.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/JsonParser.java @@ -86,7 +86,7 @@ * * @since 2201.9.0 */ -public class JsonParser { +public final class JsonParser { private static final ThreadLocal tlStateMachine = ThreadLocal.withInitial(JsonStateMachine::new); @@ -324,6 +324,7 @@ private static long convertToInt(Type targetType, String inputValue) throws Pars } } + @Override protected State finalizeObject() throws ParserException { Type targetType = this.targetTypes.get(this.targetTypes.size() - 1); switch (targetType.getTag()) { @@ -438,6 +439,7 @@ private void processRecordType(Type targetType) throws ParserException { private void processJsonAnydataType() { if (this.nodesStackSizeWhenUnionStarts == this.nodesStack.size()) { this.targetTypes.remove(this.targetTypes.size() - 1); + this.nodesStackSizeWhenUnionStarts = -1; } } @@ -445,9 +447,11 @@ private void processUnionTableFiniteType(Type targetType) { if (this.nodesStackSizeWhenUnionStarts == this.nodesStack.size()) { this.targetTypes.remove(this.targetTypes.size() - 1); this.currentJsonNode = convert(this.currentJsonNode, targetType); + this.nodesStackSizeWhenUnionStarts = -1; } } + @Override protected State initNewObject() throws ParserException { if (charBuffIndex != 0) { throw new ParserException(UNRECOGNIZED_TOKEN + "{'"); @@ -537,6 +541,7 @@ private void handleCurrentJsonNodeForObject() throws ParserException { } } + @Override protected State initNewArray() throws ParserException { if (charBuffIndex != 0) { throw new ParserException(UNRECOGNIZED_TOKEN + "['"); @@ -920,6 +925,7 @@ private void processNonStringValueAsJson(String str, ValueType type) throws Pars setValueToJsonType(type, getNonStringValueAsJson(str)); } + @Override void processNonStringValue(ValueType type) throws ParserException { String str = value(); Type targetType = this.targetTypes.get(this.targetTypes.size() - 1); @@ -996,6 +1002,7 @@ private void processArrayType(String str, ArrayType referredType) throws ParserE this.listIndices.set(this.listIndices.size() - 1, listIndex + 1); } + @Override void setValueToJsonType(ValueType type, Object value) { switch (type) { case ARRAY_ELEMENT: diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/Lists.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/Lists.java index 4d8221643933..2a545f6b5739 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/Lists.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/Lists.java @@ -29,28 +29,24 @@ * * @since 0.995.0 */ -public class Lists { +public final class Lists { + + private Lists() { + } public static Object get(ArrayValue array, long index) { if (array.getType().getTag() != TypeTags.ARRAY_TAG) { return array.getRefValue(index); } - switch (TypeUtils.getImpliedType(((BArrayType) array.getType()).getElementType()).getTag()) { - case TypeTags.BOOLEAN_TAG: - return Boolean.valueOf(array.getBoolean(index)); - case TypeTags.BYTE_TAG: - return new Long(array.getByte(index)); - case TypeTags.FLOAT_TAG: - return new Double(array.getFloat(index)); - case TypeTags.DECIMAL_TAG: - return array.getRefValue(index); - case TypeTags.INT_TAG: - return new Long((int) array.getInt(index)); - case TypeTags.STRING_TAG: - return new String(array.getString(index)); - default: - return array.getRefValue(index); - } + return switch (TypeUtils.getImpliedType(((BArrayType) array.getType()).getElementType()).getTag()) { + case TypeTags.BOOLEAN_TAG -> array.getBoolean(index); + case TypeTags.BYTE_TAG -> (long) array.getByte(index); + case TypeTags.FLOAT_TAG -> array.getFloat(index); + case TypeTags.DECIMAL_TAG -> array.getRefValue(index); + case TypeTags.INT_TAG -> array.getInt(index); + case TypeTags.STRING_TAG -> array.getString(index); + default -> array.getRefValue(index); + }; } } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/MapUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/MapUtils.java index 730910c05232..2b062de290e8 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/MapUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/MapUtils.java @@ -46,7 +46,10 @@ * * @since 0.995.0 */ -public class MapUtils { +public final class MapUtils { + + private MapUtils() { + } public static void handleMapStore(MapValue mapValue, BString fieldName, Object value) { updateMapValue(TypeUtils.getImpliedType(mapValue.getType()), mapValue, fieldName, value); @@ -66,8 +69,9 @@ public static void handleInherentTypeViolatingMapUpdate(Object value, BMapType m expType, valuesType)); } - public static boolean handleInherentTypeViolatingRecordUpdate(MapValue mapValue, BString fieldName, Object value, - BRecordType recType, boolean initialValue) { + public static boolean handleInherentTypeViolatingRecordUpdate( + MapValue mapValue, BString fieldName, Object value, + BRecordType recType, boolean initialValue) { Field recField = recType.getFields().get(fieldName.getValue()); Type recFieldType; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/MathUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/MathUtils.java index ca33da211432..8908919cd75d 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/MathUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/MathUtils.java @@ -27,10 +27,13 @@ * * @since 1.0 */ -public class MathUtils { +public final class MathUtils { private static final BString DIVIDE_BY_ZERO_ERROR = StringUtils.fromString(" / by zero"); + private MathUtils() { + } + public static long divide(long numerator, long denominator) { try { if (numerator == Long.MIN_VALUE && denominator == -1) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/RepositoryImpl.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/RepositoryImpl.java index 85b73c8b793a..002c04780501 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/RepositoryImpl.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/RepositoryImpl.java @@ -43,7 +43,7 @@ public class RepositoryImpl implements Repository { private static final String nodeId = generateNodeId(); private static String balHome; private static String balVersion; - private static boolean isRemoteEnabled = false; + private static boolean isRemoteManagementEnabled = false; @Override public List getArtifacts() { @@ -72,6 +72,11 @@ public Node getNode() { System.getProperty("os.version")); } + @Override + public boolean isRemoteManagementEnabled() { + return isRemoteManagementEnabled; + } + private Artifact createArtifact(ObjectValue service, ObjectValue listener) { ArtifactImpl artifact = new ArtifactImpl(service.toString(), Artifact.ArtifactType.SERVICE); List listeners = (List) artifact.getDetail("listeners"); @@ -87,7 +92,7 @@ private Artifact createArtifact(ObjectValue service, ObjectValue listener) { } public static void addServiceListener(BObject listener, BObject service, Object attachPoint) { - if (!isRemoteEnabled) { + if (!isRemoteManagementEnabled) { return; } BServiceType serviceType = (BServiceType) service.getType(); @@ -96,10 +101,11 @@ public static void addServiceListener(BObject listener, BObject service, Object listenerServiceMap.put((ObjectValue) listener, (ObjectValue) service); } - public static void addBallerinaRuntimeInformation(String balHome, String balVersion, boolean isRemoteEnabled) { + public static void addBallerinaRuntimeInformation(String balHome, String balVersion, + boolean isRemoteManagementEnabled) { RepositoryImpl.balHome = balHome; RepositoryImpl.balVersion = balVersion; - RepositoryImpl.isRemoteEnabled = isRemoteEnabled; + RepositoryImpl.isRemoteManagementEnabled = isRemoteManagementEnabled; } private static String generateNodeId() { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/StateMachine.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/StateMachine.java index 2babe905b4d2..c605927b1e28 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/StateMachine.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/StateMachine.java @@ -18,10 +18,10 @@ package io.ballerina.runtime.internal; +import io.ballerina.identifier.Utils; import io.ballerina.runtime.api.creators.ErrorCreator; import io.ballerina.runtime.api.utils.StringUtils; import io.ballerina.runtime.api.values.BError; -import org.apache.commons.lang3.StringEscapeUtils; import java.io.IOException; import java.io.Reader; @@ -707,7 +707,7 @@ private void reset(StateMachine sm) { } private char extractUnicodeChar(StateMachine sm) { - return StringEscapeUtils.unescapeJava("\\u" + sm.hexBuilder).charAt(0); + return Utils.unescapeJava("\\u" + sm.hexBuilder).charAt(0); } } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TableJsonDataSource.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TableJsonDataSource.java index 87c8a9e4965b..80132514c4ae 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TableJsonDataSource.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TableJsonDataSource.java @@ -47,14 +47,14 @@ */ public class TableJsonDataSource implements JsonDataSource { - private BTable tableValue; - private JSONObjectGenerator objGen; + private final BTable tableValue; + private final JSONObjectGenerator objGen; - public TableJsonDataSource(BTable tableValue) { + public TableJsonDataSource(BTable tableValue) { this(tableValue, new DefaultJSONObjectGenerator()); } - private TableJsonDataSource(BTable tableValue, JSONObjectGenerator objGen) { + private TableJsonDataSource(BTable tableValue, JSONObjectGenerator objGen) { this.tableValue = tableValue; this.objGen = objGen; } @@ -81,16 +81,12 @@ public Object next() { @Override public Object build() { ArrayValue values = new ArrayValueImpl(new BArrayType(PredefinedTypes.TYPE_JSON)); - BIterator itr = this.tableValue.getIterator(); + BIterator itr = this.tableValue.getIterator(); while (itr.hasNext()) { TupleValueImpl tupleValue = (TupleValueImpl) itr.next(); //Retrieve table value from key-value tuple - BMap record = ((BMap) tupleValue.get(1)); - try { - values.append(this.objGen.transform(record)); - } catch (IOException e) { - throw ErrorCreator.createError(e); - } + BMap record = ((BMap) tupleValue.get(1)); + values.append(this.objGen.transform(record)); } return values; } @@ -104,7 +100,7 @@ private static class DefaultJSONObjectGenerator implements JSONObjectGenerator { @Override public Object transform(BMap record) { MapValue objNode = new MapValueImpl<>(new BMapType(PredefinedTypes.TYPE_JSON)); - for (Map.Entry entry : record.entrySet()) { + for (Map.Entry entry : record.entrySet()) { Type type = TypeChecker.getType(entry.getValue()); BString keyName = StringUtils.fromString(entry.getKey().toString()); constructJsonData(record, objNode, keyName, type); @@ -152,7 +148,7 @@ private static void constructJsonData(BMap record, MapValue jsonData = new MapValueImpl<>(new BMapType(PredefinedTypes.TYPE_JSON)); - for (Map.Entry entry : record.getMapValue(key).entrySet()) { + for (Map.Entry entry : record.getMapValue(key).entrySet()) { Type internalType = TypeChecker.getType(entry.getValue()); BString internalKeyName = StringUtils.fromString(entry.getKey().toString()); constructJsonData(record.getMapValue(key), jsonData, internalKeyName, internalType); @@ -192,9 +188,8 @@ public interface JSONObjectGenerator { * * @param record The record that should be used in the current position * @return The generated JSON object - * @throws IOException for JSON reading/serializing errors */ - Object transform(BMap record) throws IOException; + Object transform(BMap record); } } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TableOmDataSource.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TableOmDataSource.java index 0dce761f0d0b..86d401f8a7bc 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TableOmDataSource.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TableOmDataSource.java @@ -51,11 +51,11 @@ public class TableOmDataSource extends AbstractPushOMDataSource { private static final String DEFAULT_ROOT_WRAPPER = "results"; private static final String DEFAULT_ROW_WRAPPER = "result"; - private TableValueImpl table; - private String rootWrapper; - private String rowWrapper; + private final TableValueImpl table; + private final String rootWrapper; + private final String rowWrapper; - public TableOmDataSource(TableValueImpl table, String rootWrapper, String rowWrapper) { + public TableOmDataSource(TableValueImpl table, String rootWrapper, String rowWrapper) { this.table = table; this.rootWrapper = rootWrapper != null ? rootWrapper : DEFAULT_ROOT_WRAPPER; this.rowWrapper = rowWrapper != null ? rowWrapper : DEFAULT_ROW_WRAPPER; @@ -64,13 +64,13 @@ public TableOmDataSource(TableValueImpl table, String rootWrapper, String rowWra @Override public void serialize(XMLStreamWriter xmlStreamWriter) throws XMLStreamException { xmlStreamWriter.writeStartElement("", this.rootWrapper, ""); - IteratorValue itr = this.table.getIterator(); + IteratorValue itr = this.table.getIterator(); while (itr.hasNext()) { table.getIterator().next(); xmlStreamWriter.writeStartElement("", this.rowWrapper, ""); TupleValueImpl tupleValue = (TupleValueImpl) itr.next(); - MapValueImpl record = ((MapValueImpl) tupleValue.get(0)); + MapValueImpl record = ((MapValueImpl) tupleValue.get(0)); BStructureType structType = (BStructureType) record.getType(); BField[] structFields = null; @@ -90,7 +90,8 @@ public void serialize(XMLStreamWriter xmlStreamWriter) throws XMLStreamException xmlStreamWriter.flush(); } - private void writeElement(MapValueImpl record, XMLStreamWriter xmlStreamWriter, String name, int type, int index, + private void writeElement(MapValueImpl record, + XMLStreamWriter xmlStreamWriter, String name, int type, int index, BField[] structFields) throws XMLStreamException { boolean isArray = false; xmlStreamWriter.writeStartElement("", name, ""); @@ -125,7 +126,7 @@ private void writeElement(MapValueImpl record, XMLStreamWriter xmlStreamWriter, BArray structData = record.getArrayValue(key); processArray(xmlStreamWriter, structData); } else { - BMap structData = record.getMapValue(key); + BMap structData = record.getMapValue(key); processStruct(xmlStreamWriter, structData, structFields, index); } break; @@ -154,7 +155,7 @@ private void processArray(XMLStreamWriter xmlStreamWriter, BArray array) throws } } - private void processStruct(XMLStreamWriter xmlStreamWriter, BMap structData, + private void processStruct(XMLStreamWriter xmlStreamWriter, BMap structData, BField[] structFields, int index) throws XMLStreamException { boolean structError = true; Type internalType = TypeUtils.getImpliedType(structFields[index].getFieldType()); @@ -167,8 +168,8 @@ private void processStruct(XMLStreamWriter xmlStreamWriter, BMap structData, BString internalKeyName = StringUtils.fromString(internalStructFields[i].getFieldName()); Object val = structData.get(internalKeyName); xmlStreamWriter.writeStartElement("", internalStructFields[i].getFieldName(), ""); - if (val instanceof MapValueImpl) { - processStruct(xmlStreamWriter, (MapValueImpl) val, internalStructFields, i); + if (val instanceof MapValueImpl mapValue) { + processStruct(xmlStreamWriter, mapValue, internalStructFields, i); } else { xmlStreamWriter.writeCharacters(val.toString()); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TableUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TableUtils.java index a2f762774b6b..cd4bade3c1c5 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TableUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TableUtils.java @@ -41,7 +41,10 @@ * @since 1.3.0 */ -public class TableUtils { +public final class TableUtils { + + private TableUtils() { + } /** * Generates a hash value which is same for the same shape. @@ -57,7 +60,7 @@ public static Long hash(Object obj, Node parent) { return 0L; } - if (obj instanceof BRefValue) { + if (obj instanceof BRefValue refValue) { Node node = new Node(obj, parent); @@ -66,19 +69,18 @@ public static Long hash(Object obj, Node parent) { .getErrorDetails(ErrorCodes.CYCLIC_VALUE_REFERENCE, TypeChecker.getType(obj))); } - BRefValue refValue = (BRefValue) obj; Type refType = TypeUtils.getImpliedType(refValue.getType()); if (refType.getTag() == TypeTags.MAP_TAG || refType.getTag() == TypeTags.RECORD_TYPE_TAG) { - MapValue mapValue = (MapValue) refValue; - for (Object entry : mapValue.entrySet()) { - result = 31 * result + hash(((Map.Entry) entry).getKey(), node) + - (((Map.Entry) entry).getValue() == null ? 0 : hash(((Map.Entry) entry).getValue(), + MapValue mapValue = (MapValue) refValue; + for (Map.Entry entry : mapValue.entrySet()) { + result = 31 * result + hash(entry.getKey(), node) + + (entry.getValue() == null ? 0 : hash(entry.getValue(), node)); } return result; } else if (refType.getTag() == TypeTags.ARRAY_TAG || refType.getTag() == TypeTags.TUPLE_TAG) { ArrayValue arrayValue = (ArrayValue) refValue; - IteratorValue arrayIterator = arrayValue.getIterator(); + IteratorValue arrayIterator = arrayValue.getIterator(); while (arrayIterator.hasNext()) { result = 31 * result + hash(arrayIterator.next(), node); } @@ -89,8 +91,8 @@ public static Long hash(Object obj, Node parent) { refType.getTag() == TypeTags.XMLNS_TAG) { return (long) refValue.toString().hashCode(); } else if (refType.getTag() == TypeTags.TABLE_TAG) { - TableValue tableValue = (TableValue) refValue; - IteratorValue tableIterator = tableValue.getIterator(); + TableValue tableValue = (TableValue) refValue; + IteratorValue tableIterator = tableValue.getIterator(); while (tableIterator.hasNext()) { result = 31 * result + hash(tableIterator.next(), node); } @@ -100,8 +102,8 @@ public static Long hash(Object obj, Node parent) { } else { return (long) obj.hashCode(); } - } else if (obj instanceof Long) { - return (long) obj; + } else if (obj instanceof Long l) { + return l; } else { return (long) obj.hashCode(); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TypeChecker.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TypeChecker.java index 1d67025453c9..908c590b9fe5 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TypeChecker.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TypeChecker.java @@ -93,7 +93,6 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; import static io.ballerina.runtime.api.PredefinedTypes.TYPE_ANY; import static io.ballerina.runtime.api.PredefinedTypes.TYPE_ANYDATA; @@ -138,7 +137,7 @@ * @since 0.995.0 */ @SuppressWarnings({"rawtypes"}) -public class TypeChecker { +public final class TypeChecker { private static final byte MAX_TYPECAST_ERROR_COUNT = 20; private static final String REG_EXP_TYPENAME = "RegExp"; @@ -361,8 +360,8 @@ public static Type getType(Object value) { return TYPE_STRING; } else if (value instanceof Boolean) { return TYPE_BOOLEAN; - } else if (value instanceof BObject) { - return ((BObject) value).getOriginalType(); + } else if (value instanceof BObject bObject) { + return bObject.getOriginalType(); } return ((BValue) value).getType(); @@ -436,60 +435,66 @@ public static boolean isReferenceEqual(Object lhsValue, Object rhsValue) { Type lhsType = getImpliedType(getType(lhsValue)); Type rhsType = getImpliedType(getType(rhsValue)); - switch (lhsType.getTag()) { - case TypeTags.FLOAT_TAG: + return switch (lhsType.getTag()) { + case TypeTags.FLOAT_TAG -> { if (rhsType.getTag() != TypeTags.FLOAT_TAG) { - return false; + yield false; } - return lhsValue.equals(((Number) rhsValue).doubleValue()); - case TypeTags.DECIMAL_TAG: + yield lhsValue.equals(((Number) rhsValue).doubleValue()); + } + case TypeTags.DECIMAL_TAG -> { if (rhsType.getTag() != TypeTags.DECIMAL_TAG) { - return false; - } - return checkDecimalExactEqual((DecimalValue) lhsValue, (DecimalValue) rhsValue); - case TypeTags.INT_TAG: - case TypeTags.BYTE_TAG: - case TypeTags.BOOLEAN_TAG: - case TypeTags.STRING_TAG: - return isEqual(lhsValue, rhsValue); - case TypeTags.XML_TAG: - case TypeTags.XML_COMMENT_TAG: - case TypeTags.XML_ELEMENT_TAG: - case TypeTags.XML_PI_TAG: - case TypeTags.XML_TEXT_TAG: + yield false; + } + yield checkDecimalExactEqual((DecimalValue) lhsValue, (DecimalValue) rhsValue); + } + case TypeTags.INT_TAG, + TypeTags.BYTE_TAG, + TypeTags.BOOLEAN_TAG, + TypeTags.STRING_TAG -> isEqual(lhsValue, rhsValue); + case TypeTags.XML_TAG, + TypeTags.XML_COMMENT_TAG, + TypeTags.XML_ELEMENT_TAG, + TypeTags.XML_PI_TAG, + TypeTags.XML_TEXT_TAG -> { if (!TypeTags.isXMLTypeTag(rhsType.getTag())) { - return false; + yield false; } - return isXMLValueRefEqual((XmlValue) lhsValue, (XmlValue) rhsValue); - case TypeTags.HANDLE_TAG: + yield isXMLValueRefEqual((XmlValue) lhsValue, (XmlValue) rhsValue); + } + case TypeTags.HANDLE_TAG -> { if (rhsType.getTag() != TypeTags.HANDLE_TAG) { - return false; + yield false; } - return isHandleValueRefEqual(lhsValue, rhsValue); - case TypeTags.FUNCTION_POINTER_TAG: - return lhsType.getPackage().equals(rhsType.getPackage()) && - lhsType.getName().equals(rhsType.getName()) && rhsType.equals(lhsType); - default: - if (lhsValue instanceof RegExpValue && rhsValue instanceof RegExpValue) { - return ((RegExpValue) lhsValue).equals(rhsValue, new HashSet<>()); + yield isHandleValueRefEqual(lhsValue, rhsValue); + } + case TypeTags.FUNCTION_POINTER_TAG -> lhsType.getPackage().equals(rhsType.getPackage()) && + lhsType.getName().equals(rhsType.getName()) && rhsType.equals(lhsType); + default -> { + if (lhsValue instanceof RegExpValue lhsRegExpValue && rhsValue instanceof RegExpValue) { + yield lhsRegExpValue.equals(rhsValue, new HashSet<>()); } - return false; - } + yield false; + } + }; } private static boolean isXMLValueRefEqual(XmlValue lhsValue, XmlValue rhsValue) { - if (lhsValue.getNodeType() == XmlNodeType.SEQUENCE && lhsValue.isSingleton()) { + boolean isLhsXmlSequence = lhsValue.getNodeType() == XmlNodeType.SEQUENCE; + boolean isRhsXmlSequence = rhsValue.getNodeType() == XmlNodeType.SEQUENCE; + + if (isLhsXmlSequence && isRhsXmlSequence) { + return isXMLSequenceRefEqual((XmlSequence) lhsValue, (XmlSequence) rhsValue); + } + if (isLhsXmlSequence && lhsValue.isSingleton()) { return ((XmlSequence) lhsValue).getChildrenList().get(0) == rhsValue; } - if (rhsValue.getNodeType() == XmlNodeType.SEQUENCE && rhsValue.isSingleton()) { + if (isRhsXmlSequence && rhsValue.isSingleton()) { return ((XmlSequence) rhsValue).getChildrenList().get(0) == lhsValue; } if (lhsValue.getNodeType() != rhsValue.getNodeType()) { return false; } - if (lhsValue.getNodeType() == XmlNodeType.SEQUENCE && rhsValue.getNodeType() == XmlNodeType.SEQUENCE) { - return isXMLSequenceRefEqual((XmlSequence) lhsValue, (XmlSequence) rhsValue); - } if (lhsValue.getNodeType() == XmlNodeType.TEXT && rhsValue.getNodeType() == XmlNodeType.TEXT) { return isEqual(lhsValue, rhsValue); } @@ -526,8 +531,8 @@ public static TypedescValue getTypedesc(Object value) { if (isSimpleBasicType(type)) { return new TypedescValueImpl(new BFiniteType(value.toString(), Set.of(value), 0)); } - if (value instanceof BRefValue) { - return (TypedescValue) ((BRefValue) value).getTypedesc(); + if (value instanceof BRefValue bRefValue) { + return (TypedescValue) bRefValue.getTypedesc(); } return new TypedescValueImpl(type); } @@ -541,10 +546,10 @@ public static TypedescValue getTypedesc(Object value) { */ public static Object getAnnotValue(TypedescValue typedescValue, BString annotTag) { Type describingType = typedescValue.getDescribingType(); - if (!(describingType instanceof BAnnotatableType)) { + if (!(describingType instanceof BAnnotatableType annotatableType)) { return null; } - return ((BAnnotatableType) describingType).getAnnotation(annotTag); + return annotatableType.getAnnotation(annotTag); } /** @@ -607,62 +612,53 @@ public static boolean checkIsType(Type sourceType, Type targetType, List sourceTypeTag == targetTypeTag; + case TypeTags.STRING_TAG -> TypeTags.isStringTypeTag(sourceTypeTag); + case TypeTags.XML_TEXT_TAG -> { if (sourceTypeTag == TypeTags.XML_TAG) { - return ((BXmlType) sourceType).constraint.getTag() == TypeTags.NEVER_TAG; - } - return sourceTypeTag == targetTypeTag; - case TypeTags.INT_TAG: - return sourceTypeTag == TypeTags.INT_TAG || sourceTypeTag == TypeTags.BYTE_TAG || - (sourceTypeTag >= TypeTags.SIGNED8_INT_TAG && sourceTypeTag <= TypeTags.UNSIGNED32_INT_TAG); - case TypeTags.SIGNED16_INT_TAG: - return sourceTypeTag == TypeTags.BYTE_TAG || - (sourceTypeTag >= TypeTags.SIGNED8_INT_TAG && sourceTypeTag <= TypeTags.SIGNED16_INT_TAG); - case TypeTags.SIGNED32_INT_TAG: - return sourceTypeTag == TypeTags.BYTE_TAG || - (sourceTypeTag >= TypeTags.SIGNED8_INT_TAG && sourceTypeTag <= TypeTags.SIGNED32_INT_TAG); - case TypeTags.UNSIGNED8_INT_TAG: - return sourceTypeTag == TypeTags.BYTE_TAG || sourceTypeTag == TypeTags.UNSIGNED8_INT_TAG; - case TypeTags.UNSIGNED16_INT_TAG: - return sourceTypeTag == TypeTags.BYTE_TAG || sourceTypeTag == TypeTags.UNSIGNED8_INT_TAG || - sourceTypeTag == TypeTags.UNSIGNED16_INT_TAG; - case TypeTags.UNSIGNED32_INT_TAG: - return sourceTypeTag == TypeTags.BYTE_TAG || sourceTypeTag == TypeTags.UNSIGNED8_INT_TAG || - sourceTypeTag == TypeTags.UNSIGNED16_INT_TAG || sourceTypeTag == TypeTags.UNSIGNED32_INT_TAG; - case TypeTags.ANY_TAG: - return checkIsAnyType(sourceType); - case TypeTags.ANYDATA_TAG: - return sourceType.isAnydata(); - case TypeTags.SERVICE_TAG: - return checkIsServiceType(sourceType, targetType, - unresolvedTypes == null ? new ArrayList<>() : unresolvedTypes); - case TypeTags.HANDLE_TAG: - return sourceTypeTag == TypeTags.HANDLE_TAG; - case TypeTags.READONLY_TAG: - return checkIsType(sourceType, PredefinedTypes.ANY_AND_READONLY_OR_ERROR_TYPE, unresolvedTypes); - case TypeTags.XML_ELEMENT_TAG: - case TypeTags.XML_COMMENT_TAG: - case TypeTags.XML_PI_TAG: - return targetTypeTag == sourceTypeTag; - case TypeTags.INTERSECTION_TAG: - return checkIsType(sourceType, ((BIntersectionType) targetType).getEffectiveType(), unresolvedTypes); - case TypeTags.TYPE_REFERENCED_TYPE_TAG: - return checkIsType(sourceType, ((BTypeReferenceType) targetType).getReferredType(), unresolvedTypes); - default: - return checkIsRecursiveType(sourceType, targetType, - unresolvedTypes == null ? new ArrayList<>() : unresolvedTypes); - } + yield ((BXmlType) sourceType).constraint.getTag() == TypeTags.NEVER_TAG; + } + yield sourceTypeTag == targetTypeTag; + } + case TypeTags.INT_TAG -> sourceTypeTag == TypeTags.INT_TAG || sourceTypeTag == TypeTags.BYTE_TAG || + (sourceTypeTag >= TypeTags.SIGNED8_INT_TAG && sourceTypeTag <= TypeTags.UNSIGNED32_INT_TAG); + case TypeTags.SIGNED16_INT_TAG -> sourceTypeTag == TypeTags.BYTE_TAG || + (sourceTypeTag >= TypeTags.SIGNED8_INT_TAG && sourceTypeTag <= TypeTags.SIGNED16_INT_TAG); + case TypeTags.SIGNED32_INT_TAG -> sourceTypeTag == TypeTags.BYTE_TAG || + (sourceTypeTag >= TypeTags.SIGNED8_INT_TAG && sourceTypeTag <= TypeTags.SIGNED32_INT_TAG); + case TypeTags.UNSIGNED8_INT_TAG -> + sourceTypeTag == TypeTags.BYTE_TAG || sourceTypeTag == TypeTags.UNSIGNED8_INT_TAG; + case TypeTags.UNSIGNED16_INT_TAG -> + sourceTypeTag == TypeTags.BYTE_TAG || sourceTypeTag == TypeTags.UNSIGNED8_INT_TAG || + sourceTypeTag == TypeTags.UNSIGNED16_INT_TAG; + case TypeTags.UNSIGNED32_INT_TAG -> + sourceTypeTag == TypeTags.BYTE_TAG || sourceTypeTag == TypeTags.UNSIGNED8_INT_TAG || + sourceTypeTag == TypeTags.UNSIGNED16_INT_TAG || + sourceTypeTag == TypeTags.UNSIGNED32_INT_TAG; + case TypeTags.ANY_TAG -> checkIsAnyType(sourceType); + case TypeTags.ANYDATA_TAG -> sourceType.isAnydata(); + case TypeTags.SERVICE_TAG -> checkIsServiceType(sourceType, targetType, + unresolvedTypes == null ? new ArrayList<>() : unresolvedTypes); + case TypeTags.HANDLE_TAG -> sourceTypeTag == TypeTags.HANDLE_TAG; + case TypeTags.READONLY_TAG -> + checkIsType(sourceType, PredefinedTypes.ANY_AND_READONLY_OR_ERROR_TYPE, unresolvedTypes); + case TypeTags.XML_ELEMENT_TAG, + TypeTags.XML_COMMENT_TAG, + TypeTags.XML_PI_TAG -> targetTypeTag == sourceTypeTag; + case TypeTags.INTERSECTION_TAG -> + checkIsType(sourceType, ((BIntersectionType) targetType).getEffectiveType(), unresolvedTypes); + case TypeTags.TYPE_REFERENCED_TYPE_TAG -> + checkIsType(sourceType, ((BTypeReferenceType) targetType).getReferredType(), unresolvedTypes); + default -> checkIsRecursiveType(sourceType, targetType, + unresolvedTypes == null ? new ArrayList<>() : unresolvedTypes); + }; } private static boolean checkIsType(Object sourceVal, Type sourceType, Type targetType, @@ -699,15 +695,12 @@ private static boolean checkIsType(Object sourceVal, Type sourceType, Type targe return false; } - switch (targetTypeTag) { - case TypeTags.ANY_TAG: - return checkIsAnyType(sourceType); - case TypeTags.READONLY_TAG: - return isInherentlyImmutableType(sourceType) || sourceType.isReadOnly(); - default: - return checkIsRecursiveTypeOnValue(sourceVal, sourceType, targetType, sourceTypeTag, targetTypeTag, - unresolvedTypes == null ? new ArrayList<>() : unresolvedTypes); - } + return switch (targetTypeTag) { + case TypeTags.ANY_TAG -> checkIsAnyType(sourceType); + case TypeTags.READONLY_TAG -> isInherentlyImmutableType(sourceType) || sourceType.isReadOnly(); + default -> checkIsRecursiveTypeOnValue(sourceVal, sourceType, targetType, sourceTypeTag, targetTypeTag, + unresolvedTypes == null ? new ArrayList<>() : unresolvedTypes); + }; } // Private methods @@ -723,72 +716,56 @@ private static boolean checkTypeDescType(Type sourceType, BTypedescType targetTy } private static boolean checkIsRecursiveType(Type sourceType, Type targetType, List unresolvedTypes) { - switch (targetType.getTag()) { - case TypeTags.MAP_TAG: - return checkIsMapType(sourceType, (BMapType) targetType, unresolvedTypes); - case TypeTags.STREAM_TAG: - return checkIsStreamType(sourceType, (BStreamType) targetType, unresolvedTypes); - case TypeTags.TABLE_TAG: - return checkIsTableType(sourceType, (BTableType) targetType, unresolvedTypes); - case TypeTags.JSON_TAG: - return checkIsJSONType(sourceType, unresolvedTypes); - case TypeTags.RECORD_TYPE_TAG: - return checkIsRecordType(sourceType, (BRecordType) targetType, unresolvedTypes); - case TypeTags.FUNCTION_POINTER_TAG: - return checkIsFunctionType(sourceType, (BFunctionType) targetType); - case TypeTags.ARRAY_TAG: - return checkIsArrayType(sourceType, (BArrayType) targetType, unresolvedTypes); - case TypeTags.TUPLE_TAG: - return checkIsTupleType(sourceType, (BTupleType) targetType, unresolvedTypes); - case TypeTags.UNION_TAG: - return checkIsUnionType(sourceType, (BUnionType) targetType, unresolvedTypes); - case TypeTags.OBJECT_TYPE_TAG: - return checkObjectEquivalency(sourceType, (BObjectType) targetType, unresolvedTypes); - case TypeTags.FINITE_TYPE_TAG: - return checkIsFiniteType(sourceType, (BFiniteType) targetType); - case TypeTags.FUTURE_TAG: - return checkIsFutureType(sourceType, (BFutureType) targetType, unresolvedTypes); - case TypeTags.ERROR_TAG: - return checkIsErrorType(sourceType, (BErrorType) targetType, unresolvedTypes); - case TypeTags.TYPEDESC_TAG: - return checkTypeDescType(sourceType, (BTypedescType) targetType, unresolvedTypes); - case TypeTags.XML_TAG: - return checkIsXMLType(sourceType, targetType, unresolvedTypes); - default: - // other non-recursive types shouldn't reach here - return false; - } + return switch (targetType.getTag()) { + case TypeTags.MAP_TAG -> checkIsMapType(sourceType, (BMapType) targetType, unresolvedTypes); + case TypeTags.STREAM_TAG -> checkIsStreamType(sourceType, (BStreamType) targetType, unresolvedTypes); + case TypeTags.TABLE_TAG -> checkIsTableType(sourceType, (BTableType) targetType, unresolvedTypes); + case TypeTags.JSON_TAG -> checkIsJSONType(sourceType, unresolvedTypes); + case TypeTags.RECORD_TYPE_TAG -> checkIsRecordType(sourceType, (BRecordType) targetType, unresolvedTypes); + case TypeTags.FUNCTION_POINTER_TAG -> checkIsFunctionType(sourceType, (BFunctionType) targetType); + case TypeTags.ARRAY_TAG -> checkIsArrayType(sourceType, (BArrayType) targetType, unresolvedTypes); + case TypeTags.TUPLE_TAG -> checkIsTupleType(sourceType, (BTupleType) targetType, unresolvedTypes); + case TypeTags.UNION_TAG -> checkIsUnionType(sourceType, (BUnionType) targetType, unresolvedTypes); + case TypeTags.OBJECT_TYPE_TAG -> + checkObjectEquivalency(sourceType, (BObjectType) targetType, unresolvedTypes); + case TypeTags.FINITE_TYPE_TAG -> checkIsFiniteType(sourceType, (BFiniteType) targetType); + case TypeTags.FUTURE_TAG -> checkIsFutureType(sourceType, (BFutureType) targetType, unresolvedTypes); + case TypeTags.ERROR_TAG -> checkIsErrorType(sourceType, (BErrorType) targetType, unresolvedTypes); + case TypeTags.TYPEDESC_TAG -> checkTypeDescType(sourceType, (BTypedescType) targetType, unresolvedTypes); + case TypeTags.XML_TAG -> checkIsXMLType(sourceType, targetType, unresolvedTypes); + // other non-recursive types shouldn't reach here + default -> false; + }; } private static boolean checkIsRecursiveTypeOnValue(Object sourceVal, Type sourceType, Type targetType, int sourceTypeTag, int targetTypeTag, List unresolvedTypes) { - switch (targetTypeTag) { - case TypeTags.ANYDATA_TAG: + return switch (targetTypeTag) { + case TypeTags.ANYDATA_TAG -> { if (sourceTypeTag == TypeTags.OBJECT_TYPE_TAG) { - return false; + yield false; } - return checkRecordBelongsToAnydataType((MapValue) sourceVal, (BRecordType) sourceType, unresolvedTypes); - case TypeTags.MAP_TAG: - return checkIsMapType(sourceVal, sourceType, (BMapType) targetType, unresolvedTypes); - case TypeTags.JSON_TAG: - return checkIsMapType(sourceVal, sourceType, - new BMapType(targetType.isReadOnly() ? TYPE_READONLY_JSON : - TYPE_JSON), unresolvedTypes); - case TypeTags.RECORD_TYPE_TAG: - return checkIsRecordType(sourceVal, sourceType, (BRecordType) targetType, unresolvedTypes); - case TypeTags.UNION_TAG: + yield checkRecordBelongsToAnydataType((MapValue) sourceVal, (BRecordType) sourceType, unresolvedTypes); + } + case TypeTags.MAP_TAG -> checkIsMapType(sourceVal, sourceType, (BMapType) targetType, unresolvedTypes); + case TypeTags.JSON_TAG -> checkIsMapType(sourceVal, sourceType, + new BMapType(targetType.isReadOnly() ? TYPE_READONLY_JSON : + TYPE_JSON), unresolvedTypes); + case TypeTags.RECORD_TYPE_TAG -> + checkIsRecordType(sourceVal, sourceType, (BRecordType) targetType, unresolvedTypes); + case TypeTags.UNION_TAG -> { for (Type type : ((BUnionType) targetType).getMemberTypes()) { if (checkIsType(sourceVal, sourceType, type, unresolvedTypes)) { - return true; + yield true; } } - return false; - case TypeTags.OBJECT_TYPE_TAG: - return checkObjectEquivalency(sourceVal, sourceType, (BObjectType) targetType, unresolvedTypes); - default: - return false; - } + yield false; + } + case TypeTags.OBJECT_TYPE_TAG -> + checkObjectEquivalency(sourceVal, sourceType, (BObjectType) targetType, unresolvedTypes); + default -> false; + }; } private static boolean isFiniteTypeMatch(BFiniteType sourceType, Type targetType) { @@ -819,22 +796,20 @@ private static boolean checkIsUnionType(Type sourceType, BUnionType targetType, } unresolvedTypes.add(pair); - switch (sourceType.getTag()) { - case TypeTags.UNION_TAG: - case TypeTags.JSON_TAG: - case TypeTags.ANYDATA_TAG: - return isUnionTypeMatch((BUnionType) sourceType, targetType, unresolvedTypes); - case TypeTags.FINITE_TYPE_TAG: - return isFiniteTypeMatch((BFiniteType) sourceType, targetType); - default: + return switch (sourceType.getTag()) { + case TypeTags.UNION_TAG, + TypeTags.JSON_TAG, + TypeTags.ANYDATA_TAG -> isUnionTypeMatch((BUnionType) sourceType, targetType, unresolvedTypes); + case TypeTags.FINITE_TYPE_TAG -> isFiniteTypeMatch((BFiniteType) sourceType, targetType); + default -> { for (Type type : targetType.getMemberTypes()) { if (checkIsType(sourceType, type, unresolvedTypes)) { - return true; + yield true; } } - return false; - - } + yield false; + } + }; } private static boolean checkIsMapType(Type sourceType, BMapType targetType, List unresolvedTypes) { @@ -857,16 +832,13 @@ private static boolean checkIsMapType(Object sourceVal, Type sourceType, BMapTyp List unresolvedTypes) { Type targetConstrainedType = targetType.getConstrainedType(); sourceType = getImpliedType(sourceType); - switch (sourceType.getTag()) { - case TypeTags.MAP_TAG: - return checkConstraints(((BMapType) sourceType).getConstrainedType(), targetConstrainedType, - unresolvedTypes); - case TypeTags.RECORD_TYPE_TAG: - return checkIsMapType((MapValue) sourceVal, (BRecordType) sourceType, unresolvedTypes, - targetConstrainedType); - default: - return false; - } + return switch (sourceType.getTag()) { + case TypeTags.MAP_TAG -> checkConstraints(((BMapType) sourceType).getConstrainedType(), + targetConstrainedType, unresolvedTypes); + case TypeTags.RECORD_TYPE_TAG -> checkIsMapType((MapValue) sourceVal, (BRecordType) sourceType, + unresolvedTypes, targetConstrainedType); + default -> false; + }; } private static boolean checkIsMapType(MapValue sourceVal, BRecordType sourceType, List unresolvedTypes, @@ -1013,7 +985,7 @@ static BField getTableConstraintField(Type constraintType, String fieldName) { BUnionType unionType = (BUnionType) constraintType; List memTypes = unionType.getMemberTypes(); List fields = memTypes.stream().map(type -> getTableConstraintField(type, fieldName)) - .filter(Objects::nonNull).collect(Collectors.toList()); + .filter(Objects::nonNull).toList(); if (fields.size() != memTypes.size()) { return null; @@ -1101,14 +1073,11 @@ private static boolean checkIsJSONType(Type sourceType, List unresolve private static boolean checkIsRecordType(Type sourceType, BRecordType targetType, List unresolvedTypes) { sourceType = getImpliedType(sourceType); - switch (sourceType.getTag()) { - case TypeTags.RECORD_TYPE_TAG: - return checkIsRecordType((BRecordType) sourceType, targetType, unresolvedTypes); - case TypeTags.MAP_TAG: - return checkIsRecordType((BMapType) sourceType, targetType, unresolvedTypes); - default: - return false; - } + return switch (sourceType.getTag()) { + case TypeTags.RECORD_TYPE_TAG -> checkIsRecordType((BRecordType) sourceType, targetType, unresolvedTypes); + case TypeTags.MAP_TAG -> checkIsRecordType((BMapType) sourceType, targetType, unresolvedTypes); + default -> false; + }; } private static boolean checkIsRecordType(BRecordType sourceRecordType, BRecordType targetType, @@ -1205,7 +1174,7 @@ private static boolean checkIsRecordType(BMapType sourceType, BRecordType target Type constraintType = sourceType.getConstrainedType(); for (Field field : targetType.getFields().values()) { - var flags = field.getFlags(); + long flags = field.getFlags(); if (!SymbolFlags.isFlagOn(flags, SymbolFlags.OPTIONAL)) { return false; } @@ -1265,14 +1234,12 @@ private static boolean checkRecordBelongsToAnydataType(MapValue sourceVal, BReco private static boolean checkIsRecordType(Object sourceVal, Type sourceType, BRecordType targetType, List unresolvedTypes) { sourceType = getImpliedType(sourceType); - switch (sourceType.getTag()) { - case TypeTags.RECORD_TYPE_TAG: - return checkIsRecordType((MapValue) sourceVal, (BRecordType) sourceType, targetType, unresolvedTypes); - case TypeTags.MAP_TAG: - return checkIsRecordType((BMapType) sourceType, targetType, unresolvedTypes); - default: - return false; - } + return switch (sourceType.getTag()) { + case TypeTags.RECORD_TYPE_TAG -> + checkIsRecordType((MapValue) sourceVal, (BRecordType) sourceType, targetType, unresolvedTypes); + case TypeTags.MAP_TAG -> checkIsRecordType((BMapType) sourceType, targetType, unresolvedTypes); + default -> false; + }; } private static boolean checkIsRecordType(MapValue sourceRecordValue, BRecordType sourceRecordType, @@ -1605,22 +1572,21 @@ private static boolean checkIsTupleType(Type sourceType, BTupleType targetType, private static boolean checkIsAnyType(Type sourceType) { sourceType = getImpliedType(sourceType); - switch (sourceType.getTag()) { - case TypeTags.ERROR_TAG: - case TypeTags.READONLY_TAG: - return false; - case TypeTags.UNION_TAG: - case TypeTags.ANYDATA_TAG: - case TypeTags.JSON_TAG: + return switch (sourceType.getTag()) { + case TypeTags.ERROR_TAG, + TypeTags.READONLY_TAG -> false; + case TypeTags.UNION_TAG, + TypeTags.ANYDATA_TAG, + TypeTags.JSON_TAG -> { for (Type memberType : ((BUnionType) sourceType).getMemberTypes()) { if (!checkIsAnyType(memberType)) { - return false; + yield false; } } - return true; - default: - return true; - } + yield true; + } + default -> true; + }; } private static boolean checkIsFiniteType(Type sourceType, BFiniteType targetType) { @@ -1928,7 +1894,7 @@ private static boolean checkIsServiceType(Type sourceType, Type targetType, List } if (sourceType.getTag() == TypeTags.OBJECT_TYPE_TAG) { - var flags = ((BObjectType) sourceType).flags; + long flags = ((BObjectType) sourceType).flags; return (flags & SymbolFlags.SERVICE) == SymbolFlags.SERVICE; } @@ -1941,27 +1907,24 @@ public static boolean isInherentlyImmutableType(Type sourceType) { return true; } - switch (sourceType.getTag()) { - case TypeTags.XML_TEXT_TAG: - case TypeTags.FINITE_TYPE_TAG: // Assuming a finite type will only have members from simple basic types. - case TypeTags.READONLY_TAG: - case TypeTags.NULL_TAG: - case TypeTags.NEVER_TAG: - case TypeTags.ERROR_TAG: - case TypeTags.INVOKABLE_TAG: - case TypeTags.SERVICE_TAG: - case TypeTags.TYPEDESC_TAG: - case TypeTags.FUNCTION_POINTER_TAG: - case TypeTags.HANDLE_TAG: - case TypeTags.REG_EXP_TYPE_TAG: - return true; - case TypeTags.XML_TAG: - return ((BXmlType) sourceType).constraint.getTag() == TypeTags.NEVER_TAG; - case TypeTags.TYPE_REFERENCED_TYPE_TAG: - return isInherentlyImmutableType(((BTypeReferenceType) sourceType).getReferredType()); - default: - return false; - } + return switch (sourceType.getTag()) { + case TypeTags.XML_TEXT_TAG, + TypeTags.FINITE_TYPE_TAG, // Assuming a finite type will only have members from simple basic types. + TypeTags.READONLY_TAG, + TypeTags.NULL_TAG, + TypeTags.NEVER_TAG, + TypeTags.ERROR_TAG, + TypeTags.INVOKABLE_TAG, + TypeTags.SERVICE_TAG, + TypeTags.TYPEDESC_TAG, + TypeTags.FUNCTION_POINTER_TAG, + TypeTags.HANDLE_TAG, + TypeTags.REG_EXP_TYPE_TAG -> true; + case TypeTags.XML_TAG -> ((BXmlType) sourceType).constraint.getTag() == TypeTags.NEVER_TAG; + case TypeTags.TYPE_REFERENCED_TYPE_TAG -> + isInherentlyImmutableType(((BTypeReferenceType) sourceType).getReferredType()); + default -> false; + }; } public static boolean isSelectivelyImmutableType(Type type, Set unresolvedTypes) { @@ -2199,85 +2162,78 @@ private static boolean checkIsLikeOnValue(List errors, Object sourceValu break; } - switch (targetTypeTag) { - case TypeTags.READONLY_TAG: - return true; - case TypeTags.BYTE_TAG: + return switch (targetTypeTag) { + case TypeTags.READONLY_TAG -> true; + case TypeTags.BYTE_TAG -> { if (TypeTags.isIntegerTypeTag(sourceTypeTag)) { - return isByteLiteral((Long) sourceValue); + yield isByteLiteral((Long) sourceValue); } - return allowNumericConversion && TypeConverter.isConvertibleToByte(sourceValue); - case TypeTags.INT_TAG: - return allowNumericConversion && TypeConverter.isConvertibleToInt(sourceValue); - case TypeTags.SIGNED32_INT_TAG: - case TypeTags.SIGNED16_INT_TAG: - case TypeTags.SIGNED8_INT_TAG: - case TypeTags.UNSIGNED32_INT_TAG: - case TypeTags.UNSIGNED16_INT_TAG: - case TypeTags.UNSIGNED8_INT_TAG: + yield allowNumericConversion && TypeConverter.isConvertibleToByte(sourceValue); + } + case TypeTags.INT_TAG -> allowNumericConversion && TypeConverter.isConvertibleToInt(sourceValue); + case TypeTags.SIGNED32_INT_TAG, + TypeTags.SIGNED16_INT_TAG, + TypeTags.SIGNED8_INT_TAG, + TypeTags.UNSIGNED32_INT_TAG, + TypeTags.UNSIGNED16_INT_TAG, + TypeTags.UNSIGNED8_INT_TAG -> { if (TypeTags.isIntegerTypeTag(sourceTypeTag)) { - return TypeConverter.isConvertibleToIntSubType(sourceValue, targetType); - } - return allowNumericConversion && TypeConverter.isConvertibleToIntSubType(sourceValue, targetType); - case TypeTags.FLOAT_TAG: - case TypeTags.DECIMAL_TAG: - return allowNumericConversion && TypeConverter.isConvertibleToFloatingPointTypes(sourceValue); - case TypeTags.CHAR_STRING_TAG: - return TypeConverter.isConvertibleToChar(sourceValue); - case TypeTags.RECORD_TYPE_TAG: - return checkIsLikeRecordType(sourceValue, (BRecordType) targetType, unresolvedValues, - allowNumericConversion, varName, errors); - case TypeTags.TABLE_TAG: - return checkIsLikeTableType(sourceValue, (BTableType) targetType, unresolvedValues, - allowNumericConversion); - case TypeTags.JSON_TAG: - return checkIsLikeJSONType(sourceValue, sourceType, (BJsonType) targetType, unresolvedValues, - allowNumericConversion); - case TypeTags.MAP_TAG: - return checkIsLikeMapType(sourceValue, (BMapType) targetType, unresolvedValues, allowNumericConversion); - case TypeTags.STREAM_TAG: - return checkIsLikeStreamType(sourceValue, (BStreamType) targetType); - case TypeTags.ARRAY_TAG: - return checkIsLikeArrayType(sourceValue, (BArrayType) targetType, unresolvedValues, - allowNumericConversion); - case TypeTags.TUPLE_TAG: - return checkIsLikeTupleType(sourceValue, (BTupleType) targetType, unresolvedValues, - allowNumericConversion); - case TypeTags.ERROR_TAG: - return checkIsLikeErrorType(sourceValue, (BErrorType) targetType, unresolvedValues, - allowNumericConversion); - case TypeTags.ANYDATA_TAG: - return checkIsLikeAnydataType(sourceValue, sourceType, unresolvedValues, allowNumericConversion); - case TypeTags.FINITE_TYPE_TAG: - return checkFiniteTypeAssignable(sourceValue, sourceType, (BFiniteType) targetType, - unresolvedValues, allowNumericConversion); - case TypeTags.XML_ELEMENT_TAG: - case TypeTags.XML_COMMENT_TAG: - case TypeTags.XML_PI_TAG: - case TypeTags.XML_TEXT_TAG: + yield TypeConverter.isConvertibleToIntSubType(sourceValue, targetType); + } + yield allowNumericConversion && TypeConverter.isConvertibleToIntSubType(sourceValue, targetType); + } + case TypeTags.FLOAT_TAG, + TypeTags.DECIMAL_TAG -> + allowNumericConversion && TypeConverter.isConvertibleToFloatingPointTypes(sourceValue); + case TypeTags.CHAR_STRING_TAG -> TypeConverter.isConvertibleToChar(sourceValue); + case TypeTags.RECORD_TYPE_TAG -> + checkIsLikeRecordType(sourceValue, (BRecordType) targetType, unresolvedValues, + allowNumericConversion, varName, errors); + case TypeTags.TABLE_TAG -> checkIsLikeTableType(sourceValue, (BTableType) targetType, unresolvedValues, + allowNumericConversion); + case TypeTags.JSON_TAG -> + checkIsLikeJSONType(sourceValue, sourceType, (BJsonType) targetType, unresolvedValues, + allowNumericConversion); + case TypeTags.MAP_TAG -> + checkIsLikeMapType(sourceValue, (BMapType) targetType, unresolvedValues, allowNumericConversion); + case TypeTags.STREAM_TAG -> checkIsLikeStreamType(sourceValue, (BStreamType) targetType); + case TypeTags.ARRAY_TAG -> checkIsLikeArrayType(sourceValue, (BArrayType) targetType, unresolvedValues, + allowNumericConversion); + case TypeTags.TUPLE_TAG -> checkIsLikeTupleType(sourceValue, (BTupleType) targetType, unresolvedValues, + allowNumericConversion); + case TypeTags.ERROR_TAG -> checkIsLikeErrorType(sourceValue, (BErrorType) targetType, unresolvedValues, + allowNumericConversion); + case TypeTags.ANYDATA_TAG -> + checkIsLikeAnydataType(sourceValue, sourceType, unresolvedValues, allowNumericConversion); + case TypeTags.FINITE_TYPE_TAG -> + checkFiniteTypeAssignable(sourceValue, sourceType, (BFiniteType) targetType, + unresolvedValues, allowNumericConversion); + case TypeTags.XML_ELEMENT_TAG, + TypeTags.XML_COMMENT_TAG, + TypeTags.XML_PI_TAG, + TypeTags.XML_TEXT_TAG -> { if (TypeTags.isXMLTypeTag(sourceTypeTag)) { - return checkIsLikeXmlValueSingleton((XmlValue) sourceValue, targetType); + yield checkIsLikeXmlValueSingleton((XmlValue) sourceValue, targetType); } - return false; - case TypeTags.XML_TAG: + yield false; + } + case TypeTags.XML_TAG -> { if (TypeTags.isXMLTypeTag(sourceTypeTag)) { - return checkIsLikeXMLSequenceType((XmlValue) sourceValue, targetType); + yield checkIsLikeXMLSequenceType((XmlValue) sourceValue, targetType); } - return false; - case TypeTags.UNION_TAG: - return checkIsLikeUnionType(errors, sourceValue, (BUnionType) targetType, unresolvedValues, - allowNumericConversion, varName); - case TypeTags.INTERSECTION_TAG: - return checkIsLikeOnValue(errors, sourceValue, sourceType, - ((BIntersectionType) targetType).getEffectiveType(), unresolvedValues, allowNumericConversion, - varName); - case TypeTags.TYPE_REFERENCED_TYPE_TAG: - return checkIsLikeOnValue(errors, sourceValue, sourceType, - ((BTypeReferenceType) targetType).getReferredType(), unresolvedValues, allowNumericConversion, - varName); - default: - return false; - } + yield false; + } + case TypeTags.UNION_TAG -> + checkIsLikeUnionType(errors, sourceValue, (BUnionType) targetType, unresolvedValues, + allowNumericConversion, varName); + case TypeTags.INTERSECTION_TAG -> checkIsLikeOnValue(errors, sourceValue, sourceType, + ((BIntersectionType) targetType).getEffectiveType(), unresolvedValues, allowNumericConversion, + varName); + case TypeTags.TYPE_REFERENCED_TYPE_TAG -> checkIsLikeOnValue(errors, sourceValue, sourceType, + ((BTypeReferenceType) targetType).getReferredType(), unresolvedValues, allowNumericConversion, + varName); + default -> false; + }; } private static boolean checkIsLikeUnionType(List errors, Object sourceValue, BUnionType targetType, @@ -2338,16 +2294,12 @@ private static boolean checkIsLikeUnionType(List errors, Object sourceVa } private static XmlNodeType getXmlNodeType(Type type) { - switch (getImpliedType(type).getTag()) { - case TypeTags.XML_ELEMENT_TAG: - return XmlNodeType.ELEMENT; - case TypeTags.XML_COMMENT_TAG: - return XmlNodeType.COMMENT; - case TypeTags.XML_PI_TAG: - return XmlNodeType.PI; - default: - return XmlNodeType.TEXT; - } + return switch (getImpliedType(type).getTag()) { + case TypeTags.XML_ELEMENT_TAG -> XmlNodeType.ELEMENT; + case TypeTags.XML_COMMENT_TAG -> XmlNodeType.COMMENT; + case TypeTags.XML_PI_TAG -> XmlNodeType.PI; + default -> XmlNodeType.TEXT; + }; } private static boolean checkIsLikeXmlValueSingleton(XmlValue xmlSource, Type targetType) { @@ -2442,17 +2394,15 @@ private static boolean checkIsLikeAnydataType(Object sourceValue, Type sourceTyp case TypeTags.ARRAY_TAG: ArrayValue arr = (ArrayValue) sourceValue; BArrayType arrayType = (BArrayType) getImpliedType(arr.getType()); - switch (getImpliedType(arrayType.getElementType()).getTag()) { - case TypeTags.INT_TAG: - case TypeTags.FLOAT_TAG: - case TypeTags.DECIMAL_TAG: - case TypeTags.STRING_TAG: - case TypeTags.BOOLEAN_TAG: - case TypeTags.BYTE_TAG: - return true; - default: - return isLikeAnydataType(arr.getValues(), unresolvedValues, allowNumericConversion); - } + return switch (getImpliedType(arrayType.getElementType()).getTag()) { + case TypeTags.INT_TAG, + TypeTags.FLOAT_TAG, + TypeTags.DECIMAL_TAG, + TypeTags.STRING_TAG, + TypeTags.BOOLEAN_TAG, + TypeTags.BYTE_TAG -> true; + default -> isLikeAnydataType(arr.getValues(), unresolvedValues, allowNumericConversion); + }; case TypeTags.TUPLE_TAG: return isLikeAnydataType(((ArrayValue) sourceValue).getValues(), unresolvedValues, allowNumericConversion); @@ -2541,10 +2491,10 @@ static boolean isUnsigned8LiteralValue(Long longObject) { static boolean isCharLiteralValue(Object object) { String value; - if (object instanceof BString) { - value = ((BString) object).getValue(); - } else if (object instanceof String) { - value = (String) object; + if (object instanceof BString bString) { + value = bString.getValue(); + } else if (object instanceof String s) { + value = s; } else { return false; } @@ -2553,11 +2503,10 @@ static boolean isCharLiteralValue(Object object) { private static boolean checkIsLikeArrayType(Object sourceValue, BArrayType targetType, List unresolvedValues, boolean allowNumericConversion) { - if (!(sourceValue instanceof ArrayValue)) { + if (!(sourceValue instanceof ArrayValue source)) { return false; } - ArrayValue source = (ArrayValue) sourceValue; Type targetTypeElementType = targetType.getElementType(); if (source.getType().getTag() == TypeTags.ARRAY_TAG) { Type sourceElementType = ((BArrayType) source.getType()).getElementType(); @@ -2607,11 +2556,11 @@ private static boolean checkIsLikeArrayType(Object sourceValue, BArrayType targe private static boolean checkIsLikeMapType(Object sourceValue, BMapType targetType, List unresolvedValues, boolean allowNumericConversion) { - if (!(sourceValue instanceof MapValueImpl)) { + if (!(sourceValue instanceof MapValueImpl sourceMapValue)) { return false; } - for (Object mapEntry : ((MapValueImpl) sourceValue).values()) { + for (Object mapEntry : sourceMapValue.values()) { if (!checkIsLikeType(null, mapEntry, targetType.getConstrainedType(), unresolvedValues, allowNumericConversion, null)) { return false; @@ -2621,11 +2570,11 @@ private static boolean checkIsLikeMapType(Object sourceValue, BMapType targetTyp } private static boolean checkIsLikeStreamType(Object sourceValue, BStreamType targetType) { - if (!(sourceValue instanceof StreamValue)) { + if (!(sourceValue instanceof StreamValue streamValue)) { return false; } - BStreamType streamType = (BStreamType) ((StreamValue) sourceValue).getType(); + BStreamType streamType = (BStreamType) streamValue.getType(); return streamType.getConstrainedType() == targetType.getConstrainedType(); } @@ -2688,7 +2637,7 @@ private static boolean checkIsMappingLikeJsonType(MapValueImpl sourceValue, BJso private static boolean checkIsLikeRecordType(Object sourceValue, BRecordType targetType, List unresolvedValues, boolean allowNumericConversion, String varName, List errors) { - if (!(sourceValue instanceof MapValueImpl)) { + if (!(sourceValue instanceof MapValueImpl sourceMapValue)) { return false; } @@ -2711,7 +2660,7 @@ private static boolean checkIsLikeRecordType(Object sourceValue, BRecordType tar String fieldNameLong = TypeConverter.getLongFieldName(varName, fieldName); Field targetField = targetType.getFields().get(fieldName); - if (!(((MapValueImpl) sourceValue).containsKey(StringUtils.fromString(fieldName))) && + if (!(sourceMapValue.containsKey(StringUtils.fromString(fieldName))) && !SymbolFlags.isFlagOn(targetField.getFlags(), SymbolFlags.OPTIONAL)) { addErrorMessage((errors == null) ? 0 : errors.size(), "missing required field '" + fieldNameLong + "' of type '" + targetField.getFieldType().toString() + "' in record '" + targetType + "'", @@ -2723,7 +2672,7 @@ private static boolean checkIsLikeRecordType(Object sourceValue, BRecordType tar } } - for (Object object : ((MapValueImpl) sourceValue).entrySet()) { + for (Object object : sourceMapValue.entrySet()) { Map.Entry valueEntry = (Map.Entry) object; String fieldName = valueEntry.getKey().toString(); String fieldNameLong = TypeConverter.getLongFieldName(varName, fieldName); @@ -2768,10 +2717,9 @@ private static void addErrorMessage(int initialErrorCount, String errorMessage, private static boolean checkIsLikeTableType(Object sourceValue, BTableType targetType, List unresolvedValues, boolean allowNumericConversion) { - if (!(sourceValue instanceof TableValueImpl)) { + if (!(sourceValue instanceof TableValueImpl tableValue)) { return false; } - TableValueImpl tableValue = (TableValueImpl) sourceValue; BTableType sourceType = (BTableType) getImpliedType(tableValue.getType()); if (targetType.getKeyType() != null && sourceType.getFieldNames().length == 0) { return false; @@ -2815,8 +2763,8 @@ private static boolean checkFiniteTypeAssignable(Object sourceValue, Type source return false; } - protected static boolean isFiniteTypeValue(Object sourceValue, Type sourceType, Object valueSpaceItem, - boolean allowNumericConversion) { + static boolean isFiniteTypeValue(Object sourceValue, Type sourceType, Object valueSpaceItem, + boolean allowNumericConversion) { Type valueSpaceItemType = getType(valueSpaceItem); int sourceTypeTag = getImpliedType(sourceType).getTag(); int valueSpaceItemTypeTag = getImpliedType(valueSpaceItemType).getTag(); @@ -3009,8 +2957,8 @@ private static boolean checkValueEquals(Object lhsValue, Object rhsValue, Set unanalyzedTypes) { !(typeTag == TypeTags.CHAR_STRING_TAG || typeTag == TypeTags.NEVER_TAG)) { return true; } - switch (typeTag) { - case TypeTags.STREAM_TAG: - case TypeTags.MAP_TAG: - case TypeTags.ANY_TAG: - return true; - case TypeTags.ARRAY_TAG: - return checkFillerValue((BArrayType) type, unanalyzedTypes); - case TypeTags.FINITE_TYPE_TAG: - return checkFillerValue((BFiniteType) type); - case TypeTags.OBJECT_TYPE_TAG: - case TypeTags.SERVICE_TAG: - return checkFillerValue((BObjectType) type); - case TypeTags.RECORD_TYPE_TAG: - return checkFillerValue((BRecordType) type, unanalyzedTypes); - case TypeTags.TUPLE_TAG: - return checkFillerValue((BTupleType) type, unanalyzedTypes); - case TypeTags.UNION_TAG: - return checkFillerValue((BUnionType) type, unanalyzedTypes); - case TypeTags.TYPE_REFERENCED_TYPE_TAG: - return hasFillerValue(((BTypeReferenceType) type).getReferredType(), unanalyzedTypes); - case TypeTags.INTERSECTION_TAG: - return hasFillerValue(((BIntersectionType) type).getEffectiveType(), unanalyzedTypes); - default: - return false; - } + return switch (typeTag) { + case TypeTags.STREAM_TAG, + TypeTags.MAP_TAG, + TypeTags.ANY_TAG -> true; + case TypeTags.ARRAY_TAG -> checkFillerValue((BArrayType) type, unanalyzedTypes); + case TypeTags.FINITE_TYPE_TAG -> checkFillerValue((BFiniteType) type); + case TypeTags.OBJECT_TYPE_TAG, + TypeTags.SERVICE_TAG -> checkFillerValue((BObjectType) type); + case TypeTags.RECORD_TYPE_TAG -> checkFillerValue((BRecordType) type, unanalyzedTypes); + case TypeTags.TUPLE_TAG -> checkFillerValue((BTupleType) type, unanalyzedTypes); + case TypeTags.UNION_TAG -> checkFillerValue((BUnionType) type, unanalyzedTypes); + case TypeTags.TYPE_REFERENCED_TYPE_TAG -> + hasFillerValue(((BTypeReferenceType) type).getReferredType(), unanalyzedTypes); + case TypeTags.INTERSECTION_TAG -> + hasFillerValue(((BIntersectionType) type).getEffectiveType(), unanalyzedTypes); + default -> false; + }; } private static boolean checkFillerValue(BTupleType tupleType, List unAnalyzedTypes) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TypeConverter.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TypeConverter.java index bac156f70b25..82f3ffbdb370 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TypeConverter.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/TypeConverter.java @@ -60,7 +60,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -95,7 +94,7 @@ * * @since 0.995.0 */ -public class TypeConverter { +public final class TypeConverter { private static final String NAN = "NaN"; private static final String POSITIVE_INFINITY = "Infinity"; @@ -109,106 +108,78 @@ public class TypeConverter { public static Object convertValues(Type targetType, Object inputValue) { Type inputType = TypeChecker.getType(inputValue); - switch (targetType.getTag()) { - case TypeTags.INT_TAG: - case TypeTags.SIGNED32_INT_TAG: - case TypeTags.SIGNED16_INT_TAG: - case TypeTags.SIGNED8_INT_TAG: - case TypeTags.UNSIGNED32_INT_TAG: - case TypeTags.UNSIGNED16_INT_TAG: - case TypeTags.UNSIGNED8_INT_TAG: - return anyToInt(inputValue, () -> - ErrorUtils.createNumericConversionError(inputValue, PredefinedTypes.TYPE_INT)); - case TypeTags.DECIMAL_TAG: - return anyToDecimal(inputValue, () -> - ErrorUtils.createNumericConversionError(inputValue, PredefinedTypes.TYPE_DECIMAL)); - case TypeTags.FLOAT_TAG: - return anyToFloat(inputValue, () -> - ErrorUtils.createNumericConversionError(inputValue, PredefinedTypes.TYPE_FLOAT)); - case TypeTags.STRING_TAG: - return StringUtils.fromString(anyToString(inputValue)); - case TypeTags.BOOLEAN_TAG: - return anyToBoolean(inputValue, () -> - ErrorUtils.createNumericConversionError(inputValue, PredefinedTypes.TYPE_BOOLEAN)); - case TypeTags.BYTE_TAG: - return anyToByte(inputValue, () -> - ErrorUtils.createNumericConversionError(inputValue, PredefinedTypes.TYPE_BYTE)); - default: - throw ErrorCreator.createError(ErrorReasons.NUMBER_CONVERSION_ERROR, - ErrorHelper.getErrorDetails( - ErrorCodes.INCOMPATIBLE_SIMPLE_TYPE_CONVERT_OPERATION, - inputType, inputValue, targetType)); - } + return switch (targetType.getTag()) { + case TypeTags.INT_TAG, + TypeTags.SIGNED32_INT_TAG, + TypeTags.SIGNED16_INT_TAG, + TypeTags.SIGNED8_INT_TAG, + TypeTags.UNSIGNED32_INT_TAG, + TypeTags.UNSIGNED16_INT_TAG, + TypeTags.UNSIGNED8_INT_TAG -> anyToInt(inputValue, () -> + ErrorUtils.createNumericConversionError(inputValue, PredefinedTypes.TYPE_INT)); + case TypeTags.DECIMAL_TAG -> anyToDecimal(inputValue, () -> + ErrorUtils.createNumericConversionError(inputValue, PredefinedTypes.TYPE_DECIMAL)); + case TypeTags.FLOAT_TAG -> anyToFloat(inputValue, () -> + ErrorUtils.createNumericConversionError(inputValue, PredefinedTypes.TYPE_FLOAT)); + case TypeTags.STRING_TAG -> StringUtils.fromString(anyToString(inputValue)); + case TypeTags.BOOLEAN_TAG -> anyToBoolean(inputValue, () -> + ErrorUtils.createNumericConversionError(inputValue, PredefinedTypes.TYPE_BOOLEAN)); + case TypeTags.BYTE_TAG -> anyToByte(inputValue, () -> + ErrorUtils.createNumericConversionError(inputValue, PredefinedTypes.TYPE_BYTE)); + default -> throw ErrorCreator.createError(ErrorReasons.NUMBER_CONVERSION_ERROR, + ErrorHelper.getErrorDetails( + ErrorCodes.INCOMPATIBLE_SIMPLE_TYPE_CONVERT_OPERATION, inputType, inputValue, targetType)); + }; } public static Object castValues(Type targetType, Object inputValue) { - switch (targetType.getTag()) { - case TypeTags.SIGNED32_INT_TAG: - return anyToSigned32(inputValue); - case TypeTags.SIGNED16_INT_TAG: - return anyToSigned16(inputValue); - case TypeTags.SIGNED8_INT_TAG: - return anyToSigned8(inputValue); - case TypeTags.UNSIGNED32_INT_TAG: - return anyToUnsigned32(inputValue); - case TypeTags.UNSIGNED16_INT_TAG: - return anyToUnsigned16(inputValue); - case TypeTags.UNSIGNED8_INT_TAG: - return anyToUnsigned8(inputValue); - case TypeTags.INT_TAG: - return anyToIntCast(inputValue, () -> - ErrorUtils.createTypeCastError(inputValue, PredefinedTypes.TYPE_INT)); - case TypeTags.DECIMAL_TAG: - return anyToDecimalCast(inputValue, () -> - ErrorUtils.createTypeCastError(inputValue, PredefinedTypes.TYPE_DECIMAL)); - case TypeTags.FLOAT_TAG: - return anyToFloatCast(inputValue, () -> - ErrorUtils.createTypeCastError(inputValue, PredefinedTypes.TYPE_FLOAT)); - case TypeTags.STRING_TAG: - return anyToStringCast(inputValue, () -> - ErrorUtils.createTypeCastError(inputValue, PredefinedTypes.TYPE_STRING)); - case TypeTags.BOOLEAN_TAG: - return anyToBooleanCast(inputValue, () -> - ErrorUtils.createTypeCastError(inputValue, PredefinedTypes.TYPE_BOOLEAN)); - case TypeTags.BYTE_TAG: - return anyToByteCast(inputValue, () -> - ErrorUtils.createTypeCastError(inputValue, PredefinedTypes.TYPE_BYTE)); - default: - throw ErrorUtils.createTypeCastError(inputValue, targetType); - } + return switch (targetType.getTag()) { + case TypeTags.SIGNED32_INT_TAG -> anyToSigned32(inputValue); + case TypeTags.SIGNED16_INT_TAG -> anyToSigned16(inputValue); + case TypeTags.SIGNED8_INT_TAG -> anyToSigned8(inputValue); + case TypeTags.UNSIGNED32_INT_TAG -> anyToUnsigned32(inputValue); + case TypeTags.UNSIGNED16_INT_TAG -> anyToUnsigned16(inputValue); + case TypeTags.UNSIGNED8_INT_TAG -> anyToUnsigned8(inputValue); + case TypeTags.INT_TAG -> anyToIntCast(inputValue, () -> + ErrorUtils.createTypeCastError(inputValue, PredefinedTypes.TYPE_INT)); + case TypeTags.DECIMAL_TAG -> anyToDecimalCast(inputValue, () -> + ErrorUtils.createTypeCastError(inputValue, PredefinedTypes.TYPE_DECIMAL)); + case TypeTags.FLOAT_TAG -> anyToFloatCast(inputValue, () -> + ErrorUtils.createTypeCastError(inputValue, PredefinedTypes.TYPE_FLOAT)); + case TypeTags.STRING_TAG -> anyToStringCast(inputValue, () -> + ErrorUtils.createTypeCastError(inputValue, PredefinedTypes.TYPE_STRING)); + case TypeTags.BOOLEAN_TAG -> anyToBooleanCast(inputValue, () -> + ErrorUtils.createTypeCastError(inputValue, PredefinedTypes.TYPE_BOOLEAN)); + case TypeTags.BYTE_TAG -> anyToByteCast(inputValue, () -> + ErrorUtils.createTypeCastError(inputValue, PredefinedTypes.TYPE_BYTE)); + default -> throw ErrorUtils.createTypeCastError(inputValue, targetType); + }; } static boolean isConvertibleToByte(Object value) { Type inputType = TypeChecker.getType(value); - switch (inputType.getTag()) { - case TypeTags.BYTE_TAG: - return true; - case TypeTags.INT_TAG: - return TypeChecker.isByteLiteral((long) value); - case TypeTags.FLOAT_TAG: + return switch (inputType.getTag()) { + case TypeTags.BYTE_TAG -> true; + case TypeTags.INT_TAG -> TypeChecker.isByteLiteral((long) value); + case TypeTags.FLOAT_TAG -> { Double doubleValue = (Double) value; - return isFloatWithinIntRange(doubleValue) && TypeChecker.isByteLiteral(doubleValue.longValue()); - case TypeTags.DECIMAL_TAG: - return isDecimalWithinIntRange((DecimalValue) value) - && TypeChecker.isByteLiteral(((DecimalValue) value).value().longValue()); - default: - return false; - } + yield isFloatWithinIntRange(doubleValue) && TypeChecker.isByteLiteral(doubleValue.longValue()); + } + case TypeTags.DECIMAL_TAG -> isDecimalWithinIntRange((DecimalValue) value) && + TypeChecker.isByteLiteral(((DecimalValue) value).value().longValue()); + default -> false; + }; } static boolean isConvertibleToInt(Object value) { Type inputType = TypeChecker.getType(value); - switch (inputType.getTag()) { - case TypeTags.BYTE_TAG: - case TypeTags.INT_TAG: - return true; - case TypeTags.FLOAT_TAG: - return isFloatWithinIntRange((double) value); - case TypeTags.DECIMAL_TAG: - return isDecimalWithinIntRange((DecimalValue) value); - default: - return false; - } + return switch (inputType.getTag()) { + case TypeTags.BYTE_TAG, + TypeTags.INT_TAG -> true; + case TypeTags.FLOAT_TAG -> isFloatWithinIntRange((double) value); + case TypeTags.DECIMAL_TAG -> isDecimalWithinIntRange((DecimalValue) value); + default -> false; + }; } static boolean isConvertibleToIntSubType(Object value, Type targetType) { @@ -260,15 +231,10 @@ static boolean isConvertibleToChar(Object value) { static boolean isConvertibleToFloatingPointTypes(Object value) { Type inputType = TypeChecker.getType(value); - switch (inputType.getTag()) { - case TypeTags.BYTE_TAG: - case TypeTags.INT_TAG: - case TypeTags.FLOAT_TAG: - case TypeTags.DECIMAL_TAG: - return true; - default: - return false; - } + return switch (inputType.getTag()) { + case TypeTags.BYTE_TAG, TypeTags.INT_TAG, TypeTags.FLOAT_TAG, TypeTags.DECIMAL_TAG -> true; + default -> false; + }; } public static Type getConvertibleType(Object inputValue, Type targetType, String varName, @@ -372,12 +338,12 @@ public static Type getConvertibleTypeInTargetUnionType(Object inputValue, BUnion for (Type memType : memberTypes) { if (TypeChecker.checkIsLikeType(inputValue, memType, false)) { - return getConvertibleType(inputValue, memType, varName, new HashSet<>(unresolvedValues), errors, false); + return getConvertibleType(inputValue, memType, varName, unresolvedValues, errors, false); } } for (Type memType : memberTypes) { - Type convertibleTypeInUnion = getConvertibleType(inputValue, memType, varName, - new HashSet<>(unresolvedValues), errors, allowNumericConversion); + Type convertibleTypeInUnion = getConvertibleType(inputValue, memType, varName, unresolvedValues, errors, + allowNumericConversion); if (convertibleTypeInUnion != null) { return convertibleTypeInUnion; } @@ -394,8 +360,8 @@ private static Type getConvertibleStructuredTypeInUnion(Object inputValue, Strin int currentErrorListSize = initialErrorListSize; for (Type memType : memberTypes) { initialErrorCount = errors.size(); - Type convertibleTypeInUnion = getConvertibleType(inputValue, memType, varName, - new HashSet<>(unresolvedValues), errors, allowNumericConversion); + Type convertibleTypeInUnion = getConvertibleType(inputValue, memType, varName, unresolvedValues, errors, + allowNumericConversion); currentErrorListSize = errors.size(); if (convertibleTypeInUnion != null) { errors.subList(initialErrorListSize - 1, currentErrorListSize).clear(); @@ -451,7 +417,7 @@ public static Type getConvertibleFiniteType(Object inputValue, BFiniteType targe private static boolean isConvertibleToRecordType(Object sourceValue, BRecordType targetType, String varName, Set unresolvedValues, List errors, boolean allowNumericConversion) { - if (!(sourceValue instanceof MapValueImpl)) { + if (!(sourceValue instanceof MapValueImpl sourceMapValueImpl)) { return false; } @@ -469,8 +435,7 @@ private static boolean isConvertibleToRecordType(Object sourceValue, BRecordType targetFieldTypes.put(field.getKey(), field.getValue().getFieldType()); } - MapValueImpl sourceMapValueImpl = (MapValueImpl) sourceValue; - for (Map.Entry targetTypeEntry : targetFieldTypes.entrySet()) { + for (Map.Entry targetTypeEntry : targetFieldTypes.entrySet()) { String fieldName = targetTypeEntry.getKey().toString(); String fieldNameLong = getLongFieldName(varName, fieldName); @@ -488,8 +453,7 @@ private static boolean isConvertibleToRecordType(Object sourceValue, BRecordType } } - for (Object object : sourceMapValueImpl.entrySet()) { - Map.Entry valueEntry = (Map.Entry) object; + for (Map.Entry valueEntry : sourceMapValueImpl.entrySet()) { String fieldName = valueEntry.getKey().toString(); String fieldNameLong = getLongFieldName(varName, fieldName); int initialErrorCount = errors.size(); @@ -519,13 +483,17 @@ private static boolean isConvertibleToRecordType(Object sourceValue, BRecordType } if ((!returnVal) && (errors.size() >= MAX_CONVERSION_ERROR_COUNT + 1)) { + unresolvedValues.remove(typeValuePair); return false; } } + if (!returnVal) { + unresolvedValues.remove(typeValuePair); + } return returnVal; } - protected static String getShortSourceValue(Object sourceValue) { + static String getShortSourceValue(Object sourceValue) { if (sourceValue == null) { return "()"; } @@ -539,7 +507,7 @@ protected static String getShortSourceValue(Object sourceValue) { return sourceValueName; } - protected static String getLongFieldName(String varName, String fieldName) { + static String getLongFieldName(String varName, String fieldName) { if (varName == null) { return fieldName; } else { @@ -616,8 +584,7 @@ private static boolean isConvertibleToMapType(Object sourceValue, BMapType targe } boolean returnVal = true; - for (Object object : ((MapValueImpl) sourceValue).entrySet()) { - Map.Entry valueEntry = (Map.Entry) object; + for (Map.Entry valueEntry : ((MapValueImpl) sourceValue).entrySet()) { String fieldNameLong = getLongFieldName(varName, valueEntry.getKey().toString()); int initialErrorCount = errors.size(); if (getConvertibleType(valueEntry.getValue(), targetType.getConstrainedType(), fieldNameLong, @@ -637,10 +604,9 @@ private static boolean isConvertibleToMapType(Object sourceValue, BMapType targe private static boolean isConvertibleToArrayType(Object sourceValue, BArrayType targetType, Set unresolvedValues, String varName, List errors, boolean allowNumericConversion) { - if (!(sourceValue instanceof ArrayValue)) { + if (!(sourceValue instanceof ArrayValue source)) { return false; } - ArrayValue source = (ArrayValue) sourceValue; int targetSize = targetType.getSize(); long sourceSize = source.getLength(); if (targetType.getState() == ArrayType.ArrayState.CLOSED && targetSize < sourceSize) { @@ -686,11 +652,10 @@ private static boolean isConvertibleToArrayType(Object sourceValue, BArrayType t private static boolean isConvertibleToTupleType(Object sourceValue, BTupleType targetType, Set unresolvedValues, String varName, List errors, boolean allowNumericConversion) { - if (!(sourceValue instanceof ArrayValue)) { + if (!(sourceValue instanceof ArrayValue source)) { return false; } - ArrayValue source = (ArrayValue) sourceValue; List targetTypes = targetType.getTupleTypes(); int sourceTypeSize = source.size(); int targetTypeSize = targetTypes.size(); @@ -747,19 +712,19 @@ private static String getElementIndex(String varName, int index) { } static long anyToInt(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof Long) { - return (Long) sourceVal; - } else if (sourceVal instanceof Double) { - return floatToInt((double) sourceVal); - } else if (sourceVal instanceof Integer) { - return ((Integer) sourceVal).longValue(); - } else if (sourceVal instanceof Boolean) { - return (Boolean) sourceVal ? 1 : 0; - } else if (sourceVal instanceof DecimalValue) { - return ((DecimalValue) sourceVal).intValue(); - } else if (sourceVal instanceof String) { + if (sourceVal instanceof Long l) { + return l; + } else if (sourceVal instanceof Double d) { + return floatToInt(d); + } else if (sourceVal instanceof Integer i) { + return i.longValue(); + } else if (sourceVal instanceof Boolean b) { + return b ? 1 : 0; + } else if (sourceVal instanceof DecimalValue decimalValue) { + return decimalValue.intValue(); + } else if (sourceVal instanceof String s) { try { - return Long.parseLong((String) sourceVal); + return Long.parseLong(s); } catch (NumberFormatException e) { throw errorFunc.get(); } @@ -769,14 +734,14 @@ static long anyToInt(Object sourceVal, Supplier errorFunc) { } static long anyToIntCast(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof Long) { - return (Long) sourceVal; - } else if (sourceVal instanceof Double) { - return floatToInt((double) sourceVal); - } else if (sourceVal instanceof Integer) { - return ((Integer) sourceVal).longValue(); - } else if (sourceVal instanceof DecimalValue) { - return ((DecimalValue) sourceVal).intValue(); + if (sourceVal instanceof Long l) { + return l; + } else if (sourceVal instanceof Double d) { + return floatToInt(d); + } else if (sourceVal instanceof Integer i) { + return i.longValue(); + } else if (sourceVal instanceof DecimalValue decimalValue) { + return decimalValue.intValue(); } else { throw errorFunc.get(); } @@ -798,19 +763,19 @@ static long anyToIntSubTypeCast(Object sourceVal, Type type, Supplier er } static double anyToFloat(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof Long) { - return ((Long) sourceVal).doubleValue(); - } else if (sourceVal instanceof Double) { - return (Double) sourceVal; - } else if (sourceVal instanceof Integer) { - return ((Integer) sourceVal).floatValue(); - } else if (sourceVal instanceof Boolean) { - return (Boolean) sourceVal ? 1.0 : 0.0; - } else if (sourceVal instanceof DecimalValue) { - return ((DecimalValue) sourceVal).floatValue(); - } else if (sourceVal instanceof String) { + if (sourceVal instanceof Long l) { + return l.doubleValue(); + } else if (sourceVal instanceof Double d) { + return d; + } else if (sourceVal instanceof Integer i) { + return i.floatValue(); + } else if (sourceVal instanceof Boolean b) { + return b ? 1.0 : 0.0; + } else if (sourceVal instanceof DecimalValue decimalValue) { + return decimalValue.floatValue(); + } else if (sourceVal instanceof String s) { try { - return Double.parseDouble((String) sourceVal); + return Double.parseDouble(s); } catch (NumberFormatException e) { throw errorFunc.get(); } @@ -820,33 +785,33 @@ static double anyToFloat(Object sourceVal, Supplier errorFunc) { } static double anyToFloatCast(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof Long) { - return ((Long) sourceVal).doubleValue(); - } else if (sourceVal instanceof Double) { - return (Double) sourceVal; - } else if (sourceVal instanceof Integer) { - return ((Integer) sourceVal).floatValue(); - } else if (sourceVal instanceof DecimalValue) { - return ((DecimalValue) sourceVal).floatValue(); + if (sourceVal instanceof Long l) { + return l.doubleValue(); + } else if (sourceVal instanceof Double d) { + return d; + } else if (sourceVal instanceof Integer i) { + return i.floatValue(); + } else if (sourceVal instanceof DecimalValue decimalValue) { + return decimalValue.floatValue(); } else { throw errorFunc.get(); } } static boolean anyToBoolean(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof Long) { - return (long) sourceVal != 0; - } else if (sourceVal instanceof Double) { - return (Double) sourceVal != 0.0; - } else if (sourceVal instanceof Integer) { - return (int) sourceVal != 0; - } else if (sourceVal instanceof Boolean) { - return (boolean) sourceVal; - } else if (sourceVal instanceof DecimalValue) { - return ((DecimalValue) sourceVal).booleanValue(); - } else if (sourceVal instanceof String) { + if (sourceVal instanceof Long l) { + return l != 0; + } else if (sourceVal instanceof Double d) { + return d != 0.0; + } else if (sourceVal instanceof Integer i) { + return i != 0; + } else if (sourceVal instanceof Boolean b) { + return b; + } else if (sourceVal instanceof DecimalValue decimalValue) { + return decimalValue.booleanValue(); + } else if (sourceVal instanceof String s) { try { - return Boolean.parseBoolean((String) sourceVal); + return Boolean.parseBoolean(s); } catch (NumberFormatException e) { throw errorFunc.get(); } @@ -965,15 +930,10 @@ public static boolean hasFloatOrDecimalLiteralSuffix(String value) { return false; } - switch (value.charAt(length - 1)) { - case 'F': - case 'f': - case 'D': - case 'd': - return true; - default: - return false; - } + return switch (value.charAt(length - 1)) { + case 'F', 'f', 'D', 'd' -> true; + default -> false; + }; } public static Boolean stringToBoolean(String value) throws NumberFormatException { @@ -1037,19 +997,19 @@ private static void checkIsValidFloat(double sourceVal, Type targetType) { } static int anyToByte(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof Long) { - return intToByte((Long) sourceVal); - } else if (sourceVal instanceof Double) { - return floatToByte((Double) sourceVal); - } else if (sourceVal instanceof Integer) { - return (int) sourceVal; - } else if (sourceVal instanceof Boolean) { - return ((Boolean) sourceVal ? 1 : 0); - } else if (sourceVal instanceof DecimalValue) { - return ((DecimalValue) sourceVal).byteValue(); - } else if (sourceVal instanceof String) { + if (sourceVal instanceof Long l) { + return intToByte(l); + } else if (sourceVal instanceof Double d) { + return floatToByte(d); + } else if (sourceVal instanceof Integer i) { + return i; + } else if (sourceVal instanceof Boolean b) { + return (b ? 1 : 0); + } else if (sourceVal instanceof DecimalValue decimalValue) { + return decimalValue.byteValue(); + } else if (sourceVal instanceof String s) { try { - return Integer.parseInt((String) sourceVal); + return Integer.parseInt(s); } catch (NumberFormatException e) { throw errorFunc.get(); } @@ -1059,16 +1019,16 @@ static int anyToByte(Object sourceVal, Supplier errorFunc) { } static int anyToByteCast(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof Long) { - return intToByte((Long) sourceVal); - } else if (sourceVal instanceof Byte) { - return ((Byte) sourceVal).intValue(); - } else if (sourceVal instanceof Double) { - return floatToByte((Double) sourceVal); - } else if (sourceVal instanceof Integer) { - return (int) sourceVal; - } else if (sourceVal instanceof DecimalValue) { - return ((DecimalValue) sourceVal).byteValue(); + if (sourceVal instanceof Long l) { + return intToByte(l); + } else if (sourceVal instanceof Byte b) { + return b.intValue(); + } else if (sourceVal instanceof Double d) { + return floatToByte(d); + } else if (sourceVal instanceof Integer i) { + return i; + } else if (sourceVal instanceof DecimalValue decimalValue) { + return decimalValue.byteValue(); } else { throw errorFunc.get(); } @@ -1076,18 +1036,18 @@ static int anyToByteCast(Object sourceVal, Supplier errorFunc) { } private static String anyToString(Object sourceVal) { - if (sourceVal instanceof Long) { - return Long.toString((Long) sourceVal); - } else if (sourceVal instanceof Double) { - return Double.toString((Double) sourceVal); - } else if (sourceVal instanceof Integer) { - return Long.toString((Integer) sourceVal); - } else if (sourceVal instanceof Boolean) { - return Boolean.toString((Boolean) sourceVal); - } else if (sourceVal instanceof DecimalValue) { - return ((DecimalValue) sourceVal).stringValue(null); - } else if (sourceVal instanceof String) { - return (String) sourceVal; + if (sourceVal instanceof Long l) { + return Long.toString(l); + } else if (sourceVal instanceof Double d) { + return Double.toString(d); + } else if (sourceVal instanceof Integer i) { + return Long.toString(i); + } else if (sourceVal instanceof Boolean b) { + return Boolean.toString(b); + } else if (sourceVal instanceof DecimalValue decimalValue) { + return decimalValue.stringValue(null); + } else if (sourceVal instanceof String s) { + return s; } else if (sourceVal == null) { return "()"; } @@ -1096,39 +1056,39 @@ private static String anyToString(Object sourceVal) { } private static String anyToStringCast(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof String) { - return (String) sourceVal; + if (sourceVal instanceof String s) { + return s; } throw errorFunc.get(); } static DecimalValue anyToDecimal(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof Long) { - return DecimalValue.valueOf((Long) sourceVal); - } else if (sourceVal instanceof Double) { - return DecimalValue.valueOf((Double) sourceVal); - } else if (sourceVal instanceof Integer) { - return DecimalValue.valueOf((Integer) sourceVal); - } else if (sourceVal instanceof Boolean) { - return DecimalValue.valueOf((Boolean) sourceVal); - } else if (sourceVal instanceof DecimalValue) { - return (DecimalValue) sourceVal; + if (sourceVal instanceof Long l) { + return DecimalValue.valueOf(l); + } else if (sourceVal instanceof Double d) { + return DecimalValue.valueOf(d); + } else if (sourceVal instanceof Integer i) { + return DecimalValue.valueOf(i); + } else if (sourceVal instanceof Boolean b) { + return DecimalValue.valueOf(b); + } else if (sourceVal instanceof DecimalValue decimalValue) { + return decimalValue; } throw errorFunc.get(); } static DecimalValue anyToDecimalCast(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof Long) { - return DecimalValue.valueOf((Long) sourceVal); - } else if (sourceVal instanceof Double) { - return DecimalValue.valueOf((Double) sourceVal); - } else if (sourceVal instanceof Integer) { - return DecimalValue.valueOf((Integer) sourceVal); - } else if (sourceVal instanceof DecimalValue) { - return (DecimalValue) sourceVal; - } else if (sourceVal instanceof String) { - return new DecimalValue((String) sourceVal); + if (sourceVal instanceof Long l) { + return DecimalValue.valueOf(l); + } else if (sourceVal instanceof Double d) { + return DecimalValue.valueOf(d); + } else if (sourceVal instanceof Integer i) { + return DecimalValue.valueOf(i); + } else if (sourceVal instanceof DecimalValue decimalValue) { + return decimalValue; + } else if (sourceVal instanceof String s) { + return new DecimalValue(s); } throw errorFunc.get(); } @@ -1136,64 +1096,64 @@ static DecimalValue anyToDecimalCast(Object sourceVal, Supplier errorFun // JBallerina related casts static byte anyToJByteCast(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof Byte) { - return (Byte) sourceVal; + if (sourceVal instanceof Byte bVal) { + return bVal; } else { throw errorFunc.get(); } } static char anyToJCharCast(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof Character) { - return (Character) sourceVal; + if (sourceVal instanceof Character cVal) { + return cVal; } else { throw errorFunc.get(); } } static short anyToJShortCast(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof Short) { - return (Short) sourceVal; + if (sourceVal instanceof Short sVal) { + return sVal; } else { throw errorFunc.get(); } } static int anyToJIntCast(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof Integer) { - return (Integer) sourceVal; + if (sourceVal instanceof Integer iVal) { + return iVal; } else { throw errorFunc.get(); } } static long anyToJLongCast(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof Long) { - return (Long) sourceVal; + if (sourceVal instanceof Long lVal) { + return lVal; } else { throw errorFunc.get(); } } static float anyToJFloatCast(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof Float) { - return (Float) sourceVal; + if (sourceVal instanceof Float fVal) { + return fVal; } else { throw errorFunc.get(); } } static double anyToJDoubleCast(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof Double) { - return (Double) sourceVal; + if (sourceVal instanceof Double dVal) { + return dVal; } else { throw errorFunc.get(); } } static boolean anyToJBooleanCast(Object sourceVal, Supplier errorFunc) { - if (sourceVal instanceof Boolean) { - return (Boolean) sourceVal; + if (sourceVal instanceof Boolean bVal) { + return bVal; } else { throw errorFunc.get(); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/ValueComparisonUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/ValueComparisonUtils.java index 4dca060da1b8..13f1010ceabc 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/ValueComparisonUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/ValueComparisonUtils.java @@ -34,7 +34,10 @@ * * @since 2.0.0 */ -public class ValueComparisonUtils { +public final class ValueComparisonUtils { + + private ValueComparisonUtils() { + } /** * Check if left hand side ordered type value is less than right hand side ordered type value. @@ -175,8 +178,8 @@ private static int compareFloatValues(double lhsValue, double rhsValue) { * @param lhsValue The value on the left hand side * @param rhsValue The value on the right hand side * @param direction Sort direction ascending/descending/"" - * @return 1 if the left hand side value > right hand side value, - * -1 if left hand side value < right hand side value, + * @return 1 if the left hand side value > right hand side value, + * -1 if left hand side value < right hand side value, * 0 left hand side value = right hand side value */ public static int compareValues(Object lhsValue, Object rhsValue, String direction) { @@ -305,14 +308,11 @@ private static int compareFloatValues(double lhsValue, double rhsValue, boolean } private static boolean checkDecimalGreaterThan(DecimalValue lhsValue, DecimalValue rhsValue) { - switch (lhsValue.valueKind) { - case ZERO: - case OTHER: - return (isDecimalRealNumber(rhsValue) && - lhsValue.decimalValue().compareTo(rhsValue.decimalValue()) > 0); - default: - return false; - } + return switch (lhsValue.valueKind) { + case ZERO, + OTHER -> (isDecimalRealNumber(rhsValue) && + lhsValue.decimalValue().compareTo(rhsValue.decimalValue()) > 0); + }; } private static boolean isDecimalRealNumber(DecimalValue decimalValue) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/ValueConverter.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/ValueConverter.java index 23ec858e2643..d29f432d9712 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/ValueConverter.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/ValueConverter.java @@ -72,7 +72,7 @@ * * @since 2201.5.0 */ -public class ValueConverter { +public final class ValueConverter { private ValueConverter() {} @@ -263,7 +263,7 @@ private static Object convertArray(BArray array, Type targetType, Type targetRef BArray data = ValueCreator .createArrayValue(tableValues, TypeCreator.createArrayType(tableType.getConstrainedType())); BArray fieldNames = StringUtils.fromStringArray(tableType.getFieldNames()); - return new TableValueImpl(targetRefType, (ArrayValue) data, (ArrayValue) fieldNames); + return new TableValueImpl<>(targetRefType, (ArrayValue) data, (ArrayValue) fieldNames); default: break; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/ValueUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/ValueUtils.java index 618e4cfaea80..82b4bb194a99 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/ValueUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/ValueUtils.java @@ -18,12 +18,9 @@ package io.ballerina.runtime.internal; import io.ballerina.runtime.api.Module; -import io.ballerina.runtime.api.async.StrandMetadata; -import io.ballerina.runtime.api.creators.ErrorCreator; import io.ballerina.runtime.api.creators.TypeCreator; import io.ballerina.runtime.api.flags.SymbolFlags; import io.ballerina.runtime.api.types.Field; -import io.ballerina.runtime.api.types.FunctionType; import io.ballerina.runtime.api.types.Type; import io.ballerina.runtime.api.utils.StringUtils; import io.ballerina.runtime.api.utils.TypeUtils; @@ -35,12 +32,10 @@ import io.ballerina.runtime.api.values.BTypedesc; import io.ballerina.runtime.api.values.BValue; import io.ballerina.runtime.api.values.BXml; -import io.ballerina.runtime.internal.scheduling.AsyncFunctionCallback; import io.ballerina.runtime.internal.scheduling.Scheduler; import io.ballerina.runtime.internal.scheduling.State; import io.ballerina.runtime.internal.scheduling.Strand; import io.ballerina.runtime.internal.types.BRecordType; -import io.ballerina.runtime.internal.values.FutureValue; import io.ballerina.runtime.internal.values.MapValue; import io.ballerina.runtime.internal.values.MapValueImpl; import io.ballerina.runtime.internal.values.TypedescValueImpl; @@ -52,18 +47,13 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; - -import static io.ballerina.runtime.api.values.BError.ERROR_PRINT_PREFIX; /** * Class @{@link ValueUtils} provides utils to create Ballerina Values. * * @since 2.0.0 */ -public class ValueUtils { +public final class ValueUtils { private static final PrintStream errStream = System.err; @@ -148,19 +138,12 @@ private static BMap populateRecordDefaultValues( BMap recordValue, Map> defaultValues) { Strand strand = Scheduler.getStrandNoException(); if (strand == null) { - try { - final CountDownLatch latch = new CountDownLatch(defaultValues.size()); - populateInitialValuesWithNoStrand(recordValue, latch, defaultValues); - latch.await(); - } catch (InterruptedException e) { - throw ErrorCreator.createError( - StringUtils.fromString("error occurred when populating default values"), e); - } - } else { - for (Map.Entry> field : defaultValues.entrySet()) { - recordValue.populateInitialValue(StringUtils.fromString(field.getKey()), - field.getValue().call(new Object[]{strand})); - } + // Create a dummy strand only for keep frames. + strand = new Strand(); + } + for (Map.Entry> field : defaultValues.entrySet()) { + recordValue.populateInitialValue(StringUtils.fromString(field.getKey()), + field.getValue().call(new Object[]{strand})); } return recordValue; } @@ -185,76 +168,6 @@ private static BMap populateRecordDefaultValues( return result; } - private static void populateInitialValuesWithNoStrand(BMap recordValue, CountDownLatch latch, - Map> defaultValues) { - String[] fields = defaultValues.keySet().toArray(new String[0]); - invokeFPAsyncIterativelyWithNoStrand(recordValue, defaultValues, fields, "default", - Scheduler.getDaemonStrand().getMetadata(), defaultValues.size(), o -> { - }, Scheduler.getDaemonStrand().scheduler, latch); - } - - public static void invokeFPAsyncIterativelyWithNoStrand(BMap recordValue, - Map> defaultValues, - String[] fields, String strandName, StrandMetadata metadata, - int noOfIterations, Consumer futureResultConsumer, - Scheduler scheduler, CountDownLatch latch) { - if (noOfIterations <= 0) { - return; - } - AtomicInteger callCount = new AtomicInteger(0); - scheduleNextFunction(recordValue, defaultValues, fields, strandName, metadata, noOfIterations, callCount, - futureResultConsumer, scheduler, latch); - } - - private static void scheduleNextFunction(BMap recordValue, - Map> defaultValues, String[] fields, - String strandName, StrandMetadata metadata, int noOfIterations, - AtomicInteger callCount, Consumer futureResultConsumer, - Scheduler scheduler, CountDownLatch latch) { - BFunctionPointer func = defaultValues.get(fields[callCount.get()]); - Type retType = ((FunctionType) TypeUtils.getImpliedType(func.getType())).getReturnType(); - FutureValue future = scheduler.createFuture(null, null, null, retType, strandName, metadata); - AsyncFunctionCallback callback = new AsyncFunctionCallback(null) { - @Override - public void notifySuccess(Object result) { - futureResultConsumer.accept(getFutureResult()); - recordValue.populateInitialValue(StringUtils.fromString(fields[callCount.get()]), result); - int i = callCount.incrementAndGet(); - latch.countDown(); - if (i != noOfIterations) { - scheduleNextFunction(recordValue, defaultValues, fields, strandName, metadata, noOfIterations, - callCount, futureResultConsumer, scheduler, latch); - } - } - - @Override - public void notifyFailure(BError error) { - errStream.println(ERROR_PRINT_PREFIX + error.getPrintableStackTrace()); - } - }; - - invokeFunctionPointerAsync(func, retType, future, callback, scheduler, strandName, metadata); - } - - private static void invokeFunctionPointerAsync(BFunctionPointer func, Type returnType, FutureValue future, - AsyncFunctionCallback callback, Scheduler scheduler, - String strandName, StrandMetadata metadata) { - future.callback = callback; - callback.setFuture(future); - AsyncFunctionCallback childCallback = new AsyncFunctionCallback(future.strand) { - @Override - public void notifySuccess(Object result) { - callback.notifySuccess(result); - } - - @Override - public void notifyFailure(BError error) { - callback.notifyFailure(error); - } - }; - scheduler.scheduleFunction(new Object[1], func, null, returnType, strandName, metadata, childCallback); - } - /** * Create a record value that populates record fields using the given package ID, record type name and a map of * field names and associated values for the fields. @@ -270,8 +183,8 @@ public static BMap createRecordValue(Module packageId, String r for (Map.Entry fieldEntry : valueMap.entrySet()) { Object val = fieldEntry.getValue(); // TODO: Remove the following String to BString conversion. - if (val instanceof String) { - val = StringUtils.fromString((String) val); + if (val instanceof String s) { + val = StringUtils.fromString(s); } recordValue.populateInitialValue(StringUtils.fromString(fieldEntry.getKey()), val); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/XmlFactory.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/XmlFactory.java index 898735fb674a..096f3c8f40c6 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/XmlFactory.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/XmlFactory.java @@ -63,7 +63,7 @@ * * @since 0.995.0 */ -public class XmlFactory { +public final class XmlFactory { public static final StAXParserConfiguration STAX_PARSER_CONFIGURATION = StAXParserConfiguration.STANDALONE; public static final String PARSE_ERROR = "failed to parse xml"; @@ -216,7 +216,7 @@ public static XmlValue concatenate(XmlValue firstSeq, XmlValue secondSeq) { * @param table {@link io.ballerina.runtime.internal.values.TableValue} to convert * @return converted {@link XmlValue} */ - public static BXml tableToXML(TableValueImpl table) { + public static BXml tableToXML(TableValueImpl table) { try { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); XMLStreamWriter streamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(outputStream); @@ -478,9 +478,8 @@ public static boolean isEqual(BXml xmlOne, BXml xmlTwo) { * * @param xmlFragment the well-formed XML fragment * @return The OMElement created out of the string XML fragment. - * @throws XMLStreamException when unexpected processing error occur while parsing. */ - public static OMElement stringToOM(String xmlFragment) throws XMLStreamException { + public static OMElement stringToOM(String xmlFragment) { return stringToOM(OMAbstractFactory.getOMFactory(), xmlFragment); } @@ -491,9 +490,8 @@ public static OMElement stringToOM(String xmlFragment) throws XMLStreamException * @param omFactory the factory used to build the object model * @param xmlFragment the well-formed XML fragment * @return The OMElement created out of the string XML fragment. - * @throws XMLStreamException when unexpected processing error occur while parsing. */ - private static OMElement stringToOM(OMFactory omFactory, String xmlFragment) throws XMLStreamException { + private static OMElement stringToOM(OMFactory omFactory, String xmlFragment) { return xmlFragment != null ? OMXMLBuilderFactory .createOMBuilder(omFactory, STAX_PARSER_CONFIGURATION, new StringReader(xmlFragment)) @@ -506,7 +504,7 @@ private static OMElement stringToOM(OMFactory omFactory, String xmlFragment) thr * * @since 1.2 */ - public static class XMLTextUnescape { + public static final class XMLTextUnescape { private XMLTextUnescape() {} diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/XmlTreeBuilder.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/XmlTreeBuilder.java index 7a287cdaa070..922215fee5c4 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/XmlTreeBuilder.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/XmlTreeBuilder.java @@ -63,17 +63,17 @@ public class XmlTreeBuilder { // XMLInputFactory2 - private static final XMLInputFactory xmlInputFactory; + private static final XMLInputFactory XML_INPUT_FACTORY; static { - xmlInputFactory = XMLInputFactory.newInstance(); - xmlInputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); + XML_INPUT_FACTORY = XMLInputFactory.newInstance(); + XML_INPUT_FACTORY.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); } private XMLStreamReader xmlStreamReader; - private Map namespaces; // xml ns declarations from Bal source [xmlns "http://ns.com" as ns] - private Deque seqDeque; - private Deque> siblingDeque; + private final Map namespaces; // xml ns declarations from Bal source [xmlns "http://ns.com" as ns] + private final Deque seqDeque; + private final Deque> siblingDeque; public XmlTreeBuilder(String str) { this(new StringReader(str)); @@ -89,7 +89,7 @@ public XmlTreeBuilder(Reader stringReader) { seqDeque.push(new XmlSequence(siblings)); try { - xmlStreamReader = xmlInputFactory.createXMLStreamReader(stringReader); + xmlStreamReader = XML_INPUT_FACTORY.createXMLStreamReader(stringReader); } catch (XMLStreamException e) { handleXMLStreamException(e); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/XmlValidator.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/XmlValidator.java index 735d21fe5b8b..0d9e69977bd8 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/XmlValidator.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/XmlValidator.java @@ -27,7 +27,7 @@ * * @since 0.995.0 */ -public class XmlValidator { +public final class XmlValidator { /* * Constants @@ -188,31 +188,31 @@ public class XmlValidator { } // remove special characters - for (int i = 0; i < specialChar.length; i++) { - CHARS[specialChar[i]] = (byte) (CHARS[specialChar[i]] & ~MASK_CONTENT); + for (int k : specialChar) { + CHARS[k] = (byte) (CHARS[k] & ~MASK_CONTENT); } // set space characters - for (int i = 0; i < spaceChar.length; i++) { - CHARS[spaceChar[i]] |= MASK_SPACE; + for (int k : spaceChar) { + CHARS[k] |= MASK_SPACE; } // set name start characters - for (int i = 0; i < nameStartChar.length; i++) { - CHARS[nameStartChar[i]] |= MASK_NAME_START | MASK_NAME | MASK_NCNAME_START | MASK_NCNAME; + for (int k : nameStartChar) { + CHARS[k] |= MASK_NAME_START | MASK_NAME | MASK_NCNAME_START | MASK_NCNAME; } for (int i = 0; i < letterRange.length; i += 2) { for (int j = letterRange[i]; j <= letterRange[i + 1]; j++) { CHARS[j] |= MASK_NAME_START | MASK_NAME | MASK_NCNAME_START | MASK_NCNAME; } } - for (int i = 0; i < letterChar.length; i++) { - CHARS[letterChar[i]] |= MASK_NAME_START | MASK_NAME | MASK_NCNAME_START | MASK_NCNAME; + for (int k : letterChar) { + CHARS[k] |= MASK_NAME_START | MASK_NAME | MASK_NCNAME_START | MASK_NCNAME; } // set name characters - for (int i = 0; i < nameChar.length; i++) { - CHARS[nameChar[i]] |= MASK_NAME | MASK_NCNAME; + for (int k : nameChar) { + CHARS[k] |= MASK_NAME | MASK_NCNAME; } for (int i = 0; i < digitRange.length; i += 2) { for (int j = digitRange[i]; j <= digitRange[i + 1]; j++) { @@ -224,24 +224,24 @@ public class XmlValidator { CHARS[j] |= MASK_NAME | MASK_NCNAME; } } - for (int i = 0; i < combiningCharChar.length; i++) { - CHARS[combiningCharChar[i]] |= MASK_NAME | MASK_NCNAME; + for (int k : combiningCharChar) { + CHARS[k] |= MASK_NAME | MASK_NCNAME; } for (int i = 0; i < extenderRange.length; i += 2) { for (int j = extenderRange[i]; j <= extenderRange[i + 1]; j++) { CHARS[j] |= MASK_NAME | MASK_NCNAME; } } - for (int i = 0; i < extenderChar.length; i++) { - CHARS[extenderChar[i]] |= MASK_NAME | MASK_NCNAME; + for (int k : extenderChar) { + CHARS[k] |= MASK_NAME | MASK_NCNAME; } // remove ':' from allowable MASK_NCNAME_START and MASK_NCNAME chars CHARS[':'] &= ~(MASK_NCNAME_START | MASK_NCNAME); // set Pubid characters - for (int i = 0; i < pubidChar.length; i++) { - CHARS[pubidChar[i]] |= MASK_PUBID; + for (int k : pubidChar) { + CHARS[k] |= MASK_PUBID; } for (int i = 0; i < pubidRange.length; i += 2) { for (int j = pubidRange[i]; j <= pubidRange[i + 1]; j++) { @@ -250,6 +250,9 @@ public class XmlValidator { } } + private XmlValidator() { + } + /* * Public Methods. */ diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/cli/CliUtil.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/cli/CliUtil.java index 353d00189704..d677e3b42be0 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/cli/CliUtil.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/cli/CliUtil.java @@ -34,7 +34,7 @@ /** * Contains the util functions for CLI parsing. */ -public class CliUtil { +public final class CliUtil { private static final String INVALID_ARGUMENT_ERROR = "invalid argument '%s' for parameter '%s', expected %s value"; @@ -64,33 +64,26 @@ static Object getUnionValue(Type type, String value, String parameterName) { } static Object getBValue(Type type, String value, String parameterName) { - switch (TypeUtils.getImpliedType(type).getTag()) { - case TypeTags.STRING_TAG: - return StringUtils.fromString(value); - case TypeTags.CHAR_STRING_TAG: - return getCharValue(value, parameterName); - case TypeTags.INT_TAG: - case TypeTags.SIGNED32_INT_TAG: - case TypeTags.SIGNED16_INT_TAG: - case TypeTags.SIGNED8_INT_TAG: - case TypeTags.UNSIGNED32_INT_TAG: - case TypeTags.UNSIGNED16_INT_TAG: - case TypeTags.UNSIGNED8_INT_TAG: - return getIntegerValue(value, parameterName); - case TypeTags.BYTE_TAG: - return getByteValue(value, parameterName); - case TypeTags.FLOAT_TAG: - return getFloatValue(value, parameterName); - case TypeTags.DECIMAL_TAG: - return getDecimalValue(value, parameterName); - case TypeTags.TYPE_REFERENCED_TYPE_TAG: - return getBValue(TypeUtils.getImpliedType(type), value, parameterName); - case TypeTags.BOOLEAN_TAG: - throw ErrorCreator.createError(StringUtils.fromString("the option '" + parameterName + "' of type " + - "'boolean' is expected without a value")); - default: - throw getUnsupportedTypeException(type); - } + return switch (TypeUtils.getImpliedType(type).getTag()) { + case TypeTags.STRING_TAG -> StringUtils.fromString(value); + case TypeTags.CHAR_STRING_TAG -> getCharValue(value, parameterName); + case TypeTags.INT_TAG, + TypeTags.SIGNED32_INT_TAG, + TypeTags.SIGNED16_INT_TAG, + TypeTags.SIGNED8_INT_TAG, + TypeTags.UNSIGNED32_INT_TAG, + TypeTags.UNSIGNED16_INT_TAG, + TypeTags.UNSIGNED8_INT_TAG -> getIntegerValue(value, parameterName); + case TypeTags.BYTE_TAG -> getByteValue(value, parameterName); + case TypeTags.FLOAT_TAG -> getFloatValue(value, parameterName); + case TypeTags.DECIMAL_TAG -> getDecimalValue(value, parameterName); + case TypeTags.TYPE_REFERENCED_TYPE_TAG -> getBValue(TypeUtils.getImpliedType(type), value, parameterName); + case TypeTags.BOOLEAN_TAG -> + throw ErrorCreator.createError( + StringUtils.fromString("the option '" + parameterName + "' of type " + + "'boolean' is expected without a value")); + default -> throw getUnsupportedTypeException(type); + }; } private static Object getCharValue(String argument, String parameterName) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/commons/TypeValuePair.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/commons/TypeValuePair.java index e081a73a2c9e..783366fad499 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/commons/TypeValuePair.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/commons/TypeValuePair.java @@ -40,10 +40,9 @@ public boolean equals(Object o) { if (o == this) { return true; } - if (!(o instanceof TypeValuePair)) { + if (!(o instanceof TypeValuePair other)) { return false; } - TypeValuePair other = (TypeValuePair) o; boolean sourceValueEquals = (this.sourceValue == null && other.sourceValue == null) || (this.sourceValue != null && this.sourceValue.equals(other.sourceValue)); boolean targetTypeEquals = (this.targetType == null && other.targetType == null) diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/ConfigMap.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/ConfigMap.java index 36684efd0bab..933afc55a8d1 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/ConfigMap.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/ConfigMap.java @@ -26,7 +26,8 @@ * * @since 2.0.0 */ -public class ConfigMap { +public final class ConfigMap { + private static Map configurableMap = new HashMap<>(); private ConfigMap() {} diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/exceptions/ConfigException.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/exceptions/ConfigException.java index 1ff6ac54b588..dbf434c134bd 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/exceptions/ConfigException.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/exceptions/ConfigException.java @@ -27,9 +27,9 @@ */ public class ConfigException extends RuntimeException { - private ErrorCodes errorCode; + private final ErrorCodes errorCode; - private Object[] args; + private final Object[] args; public ConfigException(ErrorCodes errorCode, Object... args) { this.errorCode = errorCode; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/ConfigUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/ConfigUtils.java index 85e2dcab2742..4c559b4594cf 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/ConfigUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/ConfigUtils.java @@ -40,7 +40,7 @@ /* * Util class that contain methods that are common for env vars, cli configuration. */ -public class ConfigUtils { +public final class ConfigUtils { private ConfigUtils() { } @@ -77,15 +77,15 @@ public static Object getFiniteBalValue(String strValue, BFiniteType finiteType, public static boolean containsUnsupportedMembers(BUnionType unionType) { for (Type memberType : unionType.getMemberTypes()) { - if (!isSimpleSequenceType(TypeUtils.getImpliedType(memberType).getTag())) { + if (!isPrimitiveOrSequenceType(TypeUtils.getImpliedType(memberType).getTag())) { return true; } } return false; } - private static boolean isSimpleSequenceType(int tag) { - return tag <= TypeTags.BOOLEAN_TAG || TypeTags.isXMLTypeTag(tag); + private static boolean isPrimitiveOrSequenceType(int tag) { + return tag == TypeTags.NULL_TAG || tag <= TypeTags.BOOLEAN_TAG || TypeTags.isXMLTypeTag(tag); } public static Object getUnionValue(VariableKey key, BUnionType unionType, String value, String arg) { @@ -104,6 +104,8 @@ private static List getConvertibleMemberValues(String value, UnionType u List matchingValues = new ArrayList<>(); for (Type type : unionType.getMemberTypes()) { switch (TypeUtils.getImpliedType(type).getTag()) { + case TypeTags.NULL_TAG: + break; case TypeTags.BYTE_TAG: convertAndGetValuesFromString(matchingValues, TypeConverter::stringToByte, value); break; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/cli/CliConstants.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/cli/CliConstants.java index dab0f6cff317..818608a893c5 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/cli/CliConstants.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/cli/CliConstants.java @@ -23,7 +23,7 @@ * * @since 2.0.0 */ -public class CliConstants { +public final class CliConstants { static final String CLI_PREFIX = "-C"; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/cli/CliProvider.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/cli/CliProvider.java index 182b01135066..003998ff95d3 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/cli/CliProvider.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/cli/CliProvider.java @@ -220,12 +220,12 @@ public Optional getAsUnionAndMark(Module module, VariableKey key) { CliArg cliArg = getCliArg(module, key); BUnionType unionType = (BUnionType) ((BIntersectionType) key.type).getEffectiveType(); boolean isEnum = SymbolFlags.isFlagOn(unionType.getFlags(), SymbolFlags.ENUM); - if (!isEnum && ConfigUtils.containsUnsupportedMembers(unionType)) { - throw new ConfigException(CONFIG_CLI_TYPE_NOT_SUPPORTED, key.variable, unionType); - } if (cliArg.value == null) { return Optional.empty(); } + if (!isEnum && ConfigUtils.containsUnsupportedMembers(unionType)) { + throw new ConfigException(CONFIG_CLI_TYPE_NOT_SUPPORTED, key.variable, unionType); + } if (isEnum) { return getCliConfigValue(ConfigUtils.getFiniteValue(key, unionType, cliArg.value, cliArg.toString())); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/env/EnvVarProvider.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/env/EnvVarProvider.java index 63194d79965e..78cc5992c94f 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/env/EnvVarProvider.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/env/EnvVarProvider.java @@ -333,7 +333,7 @@ private EnvVar markAndGetEnvVar(String key, VariableKey variableKey, String valu return new EnvVar(key, value); } - public class EnvVar { + public static class EnvVar { public String key; public String value; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/toml/ConfigValueCreator.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/toml/ConfigValueCreator.java index e68b45d216ff..7c2c7164b131 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/toml/ConfigValueCreator.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/toml/ConfigValueCreator.java @@ -195,18 +195,11 @@ private BArray getStructuredValueArray(TomlNode tomlValue, ArrayType arrayType, } private ListInitialValueEntry.ExpressionEntry[] getListEntries(TomlNode tomlValue, Type elementType) { - ListInitialValueEntry.ExpressionEntry[] entries; - switch (tomlValue.kind()) { - case ARRAY: - entries = createInitialValuesFromArrayNode((TomlArrayValueNode) tomlValue, elementType); - break; - case TABLE_ARRAY: - entries = createInitialValuesFromTableArrayNode((TomlTableArrayNode) tomlValue, elementType); - break; - default: - entries = getListEntries(((TomlKeyValueNode) tomlValue).value(), elementType); - } - return entries; + return switch (tomlValue.kind()) { + case ARRAY -> createInitialValuesFromArrayNode((TomlArrayValueNode) tomlValue, elementType); + case TABLE_ARRAY -> createInitialValuesFromTableArrayNode((TomlTableArrayNode) tomlValue, elementType); + default -> getListEntries(((TomlKeyValueNode) tomlValue).value(), elementType); + }; } private BArray createArrayFromSimpleTomlValue(TomlArrayValueNode tomlValue, ArrayType arrayType, @@ -224,27 +217,20 @@ private BArray createArrayFromSimpleTomlValue(TomlArrayValueNode tomlValue, Arra } private Object getElementValue(Type elementType, TomlNode tomlValueNode) { - Object balValue; Type refElementType = TypeUtils.getImpliedType(elementType); - switch (refElementType.getTag()) { - case TypeTags.ARRAY_TAG: + return switch (refElementType.getTag()) { + case TypeTags.ARRAY_TAG -> { ArrayType arrayType = (ArrayType) refElementType; - balValue = createArrayFromSimpleTomlValue( + yield createArrayFromSimpleTomlValue( (TomlArrayValueNode) tomlValueNode, arrayType, TypeUtils.getImpliedType(arrayType.getElementType())); - break; - case TypeTags.ANYDATA_TAG: - case TypeTags.UNION_TAG: - case TypeTags.JSON_TAG: - balValue = createUnionValue(tomlValueNode, (BUnionType) refElementType); - break; - case TypeTags.TUPLE_TAG: - balValue = createTupleValue(tomlValueNode, (TupleType) refElementType); - break; - default: - balValue = createBalValue(elementType, (TomlValueNode) tomlValueNode); - } - return balValue; + } + case TypeTags.ANYDATA_TAG, + TypeTags.UNION_TAG, + TypeTags.JSON_TAG -> createUnionValue(tomlValueNode, (BUnionType) refElementType); + case TypeTags.TUPLE_TAG -> createTupleValue(tomlValueNode, (TupleType) refElementType); + default -> createBalValue(elementType, (TomlValueNode) tomlValueNode); + }; } private BMap createRecordValue(TomlNode tomlNode, Type type) { @@ -331,23 +317,18 @@ private ListInitialValueEntry.ExpressionEntry[] createInitialValuesFromTableArra private Object createBalValue(Type type, TomlValueNode tomlValueNode) { Object tomlValue = ((TomlBasicValueNode) tomlValueNode).getValue(); - switch (TypeUtils.getImpliedType(type).getTag()) { - case TypeTags.BYTE_TAG: - return ((Long) tomlValue).intValue(); - case TypeTags.DECIMAL_TAG: - return ValueCreator.createDecimalValue(BigDecimal.valueOf((Double) tomlValue)); - case TypeTags.STRING_TAG: - return StringUtils.fromString((String) tomlValue); - case TypeTags.XML_ATTRIBUTES_TAG: - case TypeTags.XML_COMMENT_TAG: - case TypeTags.XML_ELEMENT_TAG: - case TypeTags.XML_PI_TAG: - case TypeTags.XML_TAG: - case TypeTags.XML_TEXT_TAG: - return createReadOnlyXmlValue((String) tomlValue); - default: - return tomlValue; - } + return switch (TypeUtils.getImpliedType(type).getTag()) { + case TypeTags.BYTE_TAG -> ((Long) tomlValue).intValue(); + case TypeTags.DECIMAL_TAG -> ValueCreator.createDecimalValue(BigDecimal.valueOf((Double) tomlValue)); + case TypeTags.STRING_TAG -> StringUtils.fromString((String) tomlValue); + case TypeTags.XML_ATTRIBUTES_TAG, + TypeTags.XML_COMMENT_TAG, + TypeTags.XML_ELEMENT_TAG, + TypeTags.XML_PI_TAG, + TypeTags.XML_TAG, + TypeTags.XML_TEXT_TAG -> createReadOnlyXmlValue((String) tomlValue); + default -> tomlValue; + }; } private BMap createMapValue(TomlNode tomlValue, MapType mapType) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/toml/TomlConfigValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/toml/TomlConfigValue.java index 95c8263e837d..2904df9439fd 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/toml/TomlConfigValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/toml/TomlConfigValue.java @@ -39,8 +39,8 @@ public TomlConfigValue(Object value, Type type) { @Override public Object getValue() { - if (value instanceof TomlNode) { - return valueCreator.createValue((TomlNode) value, type); + if (value instanceof TomlNode tomlNode) { + return valueCreator.createValue(tomlNode, type); } return value; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/toml/TomlConstants.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/toml/TomlConstants.java index 1658a2b47eb6..7d28f92110cd 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/toml/TomlConstants.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/toml/TomlConstants.java @@ -21,21 +21,21 @@ import io.ballerina.runtime.internal.util.RuntimeUtils; import java.nio.file.Path; -import java.nio.file.Paths; /** * Constants used by toml parser. * * @since 2.0.0 */ -public class TomlConstants { +public final class TomlConstants { + public static final String CONFIG_FILE_NAME = "Config.toml"; public static final String ENV_VAR_PREFIX = "BAL_CONFIG_VAR_"; public static final String CONFIG_FILES_ENV_VARIABLE = "BAL_CONFIG_FILES"; public static final String CONFIG_DATA_ENV_VARIABLE = "BAL_CONFIG_DATA"; public static final String MODULES_ROOT = "modules"; public static final String TEST_DIR_NAME = "tests"; - public static final Path DEFAULT_CONFIG_PATH = Paths.get(RuntimeUtils.USER_DIR, CONFIG_FILE_NAME); + public static final Path DEFAULT_CONFIG_PATH = Path.of(RuntimeUtils.USER_DIR, CONFIG_FILE_NAME); private TomlConstants() { } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/toml/Utils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/toml/Utils.java index feae819df6db..86d2615bc0b5 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/toml/Utils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/configurable/providers/toml/Utils.java @@ -78,7 +78,7 @@ * * @since 2.0.0 */ -public class Utils { +public final class Utils { private static final Type TYPE_READONLY_ANYDATA_INTERSECTION = new BIntersectionType(null, new Type[]{TYPE_READONLY_ANYDATA}, @@ -88,59 +88,40 @@ private Utils() { } static Object getTomlTypeString(TomlNode tomlNode) { - switch (tomlNode.kind()) { - case STRING: - return "string"; - case INTEGER: - return "int"; - case DOUBLE: - return "float"; - case BOOLEAN: - return "boolean"; - case ARRAY: - return "array"; - case TABLE: - case INLINE_TABLE: - return "record"; - case TABLE_ARRAY: - return "table"; - case KEY_VALUE: - return getTomlTypeString(((TomlKeyValueNode) tomlNode).value()); - default: - return "unsupported type"; - } + return switch (tomlNode.kind()) { + case STRING -> "string"; + case INTEGER -> "int"; + case DOUBLE -> "float"; + case BOOLEAN -> "boolean"; + case ARRAY -> "array"; + case TABLE, INLINE_TABLE -> "record"; + case TABLE_ARRAY -> "table"; + case KEY_VALUE -> getTomlTypeString(((TomlKeyValueNode) tomlNode).value()); + default -> "unsupported type"; + }; } static Object getBalValueFromToml(TomlNode tomlNode, Set visitedNodes, BUnionType unionType, Set invalidTomlLines, String variableName) { visitedNodes.add(tomlNode); - switch (tomlNode.kind()) { - case STRING: - return validateAndGetStringValue((TomlStringValueNode) tomlNode, unionType, invalidTomlLines, - variableName); - case INTEGER: - return ((TomlLongValueNode) tomlNode).getValue(); - case DOUBLE: - return validateAndGetDoubleValue((TomlDoubleValueNodeNode) tomlNode, unionType, invalidTomlLines, - variableName); - case BOOLEAN: - return ((TomlBooleanValueNode) tomlNode).getValue(); - case KEY_VALUE: - return getBalValueFromToml(((TomlKeyValueNode) tomlNode).value(), visitedNodes, unionType, - invalidTomlLines, variableName); - case ARRAY: - return getAnydataArray((TomlArrayValueNode) tomlNode, visitedNodes, invalidTomlLines, variableName); - case TABLE: - return getAnydataMap((TomlTableNode) tomlNode, visitedNodes, invalidTomlLines, variableName); - case TABLE_ARRAY: - return getMapAnydataArray((TomlTableArrayNode) tomlNode, visitedNodes, invalidTomlLines, variableName); - case INLINE_TABLE: - return getAnydataMap(((TomlInlineTableValueNode) tomlNode).toTable(), visitedNodes, invalidTomlLines, - variableName); - default: - // should not come here - return null; - } + return switch (tomlNode.kind()) { + case STRING -> validateAndGetStringValue( + (TomlStringValueNode) tomlNode, unionType, invalidTomlLines, variableName); + case INTEGER -> ((TomlLongValueNode) tomlNode).getValue(); + case DOUBLE -> validateAndGetDoubleValue( + (TomlDoubleValueNodeNode) tomlNode, unionType, invalidTomlLines, variableName); + case BOOLEAN -> ((TomlBooleanValueNode) tomlNode).getValue(); + case KEY_VALUE -> getBalValueFromToml( + ((TomlKeyValueNode) tomlNode).value(), visitedNodes, unionType, invalidTomlLines, variableName); + case ARRAY -> getAnydataArray((TomlArrayValueNode) tomlNode, visitedNodes, invalidTomlLines, variableName); + case TABLE -> getAnydataMap((TomlTableNode) tomlNode, visitedNodes, invalidTomlLines, variableName); + case TABLE_ARRAY -> getMapAnydataArray( + (TomlTableArrayNode) tomlNode, visitedNodes, invalidTomlLines, variableName); + case INLINE_TABLE -> getAnydataMap( + ((TomlInlineTableValueNode) tomlNode).toTable(), visitedNodes, invalidTomlLines, variableName); + // should not come here + default -> null; + }; } private static Object getAnydataMap(TomlTableNode tomlNode, Set visitedNodes, @@ -183,38 +164,31 @@ private static Object getMapAnydataArray(TomlTableArrayNode tomlNode, Set kind == TomlType.INTEGER; + case TypeTags.BOOLEAN_TAG -> kind == TomlType.BOOLEAN; + case TypeTags.FLOAT_TAG, + TypeTags.DECIMAL_TAG -> kind == TomlType.DOUBLE; + case TypeTags.STRING_TAG, + TypeTags.UNION_TAG, + TypeTags.XML_ATTRIBUTES_TAG, + TypeTags.XML_COMMENT_TAG, + TypeTags.XML_ELEMENT_TAG, + TypeTags.XML_PI_TAG, + TypeTags.XML_TAG, + TypeTags.XML_TEXT_TAG -> kind == TomlType.STRING; + case TypeTags.ARRAY_TAG, + TypeTags.TUPLE_TAG -> kind == TomlType.ARRAY; + case TypeTags.MAP_TAG, + TypeTags.RECORD_TYPE_TAG -> kind == TomlType.INLINE_TABLE || kind == TomlType.TABLE; + case TypeTags.TABLE_TAG -> kind == TomlType.TABLE_ARRAY || kind == TomlType.ARRAY; + case TypeTags.INTERSECTION_TAG -> { Type effectiveType = ((IntersectionType) expectedType).getEffectiveType(); - return checkEffectiveTomlType(kind, effectiveType, variableName); - default: - throw new ConfigException(CONFIG_TYPE_NOT_SUPPORTED, variableName, expectedType.toString()); - } + yield checkEffectiveTomlType(kind, effectiveType, variableName); + } + default -> throw new ConfigException(CONFIG_TYPE_NOT_SUPPORTED, variableName, expectedType.toString()); + }; } static boolean isSimpleType(int typeTag) { @@ -241,31 +215,23 @@ static LineRange getOneBasedLineRange(LineRange lineRange) { } public static Type getTypeFromTomlValue(TomlNode tomlNode) { - switch (tomlNode.kind()) { - case STRING: - return PredefinedTypes.TYPE_STRING; - case INTEGER: - return PredefinedTypes.TYPE_INT; - case DOUBLE: - return PredefinedTypes.TYPE_FLOAT; - case BOOLEAN: - return PredefinedTypes.TYPE_BOOLEAN; - case KEY_VALUE: - return getTypeFromTomlValue(((TomlKeyValueNode) tomlNode).value()); - case ARRAY: + return switch (tomlNode.kind()) { + case STRING -> PredefinedTypes.TYPE_STRING; + case INTEGER -> PredefinedTypes.TYPE_INT; + case DOUBLE -> PredefinedTypes.TYPE_FLOAT; + case BOOLEAN -> PredefinedTypes.TYPE_BOOLEAN; + case KEY_VALUE -> getTypeFromTomlValue(((TomlKeyValueNode) tomlNode).value()); + case ARRAY -> { if (containsInlineTable((TomlArrayValueNode) tomlNode)) { - return TypeCreator.createArrayType(TypeCreator.createMapType(TYPE_ANYDATA), true); + yield TypeCreator.createArrayType(TypeCreator.createMapType(TYPE_ANYDATA), true); } - return TypeCreator.createArrayType(TYPE_ANYDATA, true); - case TABLE: - case INLINE_TABLE: - return TypeCreator.createMapType(TYPE_ANYDATA, true); - case TABLE_ARRAY: - return TypeCreator.createArrayType(TypeCreator.createMapType(TYPE_ANYDATA), true); - default: - // should not come here - return null; - } + yield TypeCreator.createArrayType(TYPE_ANYDATA, true); + } + case TABLE, INLINE_TABLE -> TypeCreator.createMapType(TYPE_ANYDATA, true); + case TABLE_ARRAY -> TypeCreator.createArrayType(TypeCreator.createMapType(TYPE_ANYDATA), true); + // should not come here + default -> null; + }; } private static boolean containsInlineTable(TomlArrayValueNode tomlNode) { @@ -385,14 +351,11 @@ static boolean isXMLType(Type type) { } static Type getEffectiveType(Type type) { - switch (type.getTag()) { - case TypeTags.INTERSECTION_TAG: - return ((IntersectionType) type).getEffectiveType(); - case TypeTags.TYPE_REFERENCED_TYPE_TAG: - return getEffectiveType(((ReferenceType) type).getReferredType()); - default: - return type; - } + return switch (type.getTag()) { + case TypeTags.INTERSECTION_TAG -> ((IntersectionType) type).getEffectiveType(); + case TypeTags.TYPE_REFERENCED_TYPE_TAG -> getEffectiveType(((ReferenceType) type).getReferredType()); + default -> type; + }; } private static boolean isMappingType(int typeTag) { @@ -412,23 +375,17 @@ public static Object getFiniteBalValue(TomlNode tomlNode, Set visitedN BFiniteType finiteType, Set invalidTomlLines, String variableName) { visitedNodes.add(tomlNode); - switch (tomlNode.kind()) { - case STRING: - return StringUtils.fromString(((TomlStringValueNode) tomlNode).getValue()); - case INTEGER: - return ((TomlLongValueNode) tomlNode).getValue(); - case DOUBLE: - return validateAndGetFiniteDoubleValue((TomlDoubleValueNodeNode) tomlNode, finiteType, invalidTomlLines, - variableName); - case BOOLEAN: - return ((TomlBooleanValueNode) tomlNode).getValue(); - case KEY_VALUE: - return getFiniteBalValue(((TomlKeyValueNode) tomlNode).value(), visitedNodes, finiteType, - invalidTomlLines, variableName); - default: - // should not come here - return null; - } + return switch (tomlNode.kind()) { + case STRING -> StringUtils.fromString(((TomlStringValueNode) tomlNode).getValue()); + case INTEGER -> ((TomlLongValueNode) tomlNode).getValue(); + case DOUBLE -> validateAndGetFiniteDoubleValue( + (TomlDoubleValueNodeNode) tomlNode, finiteType, invalidTomlLines, variableName); + case BOOLEAN -> ((TomlBooleanValueNode) tomlNode).getValue(); + case KEY_VALUE -> getFiniteBalValue( + ((TomlKeyValueNode) tomlNode).value(), visitedNodes, finiteType, invalidTomlLines, variableName); + // should not come here + default -> null; + }; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/diagnostics/RuntimeDiagnostic.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/diagnostics/RuntimeDiagnostic.java index 3f2ccf22c317..868927bce53a 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/diagnostics/RuntimeDiagnostic.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/diagnostics/RuntimeDiagnostic.java @@ -35,9 +35,9 @@ public class RuntimeDiagnostic extends Diagnostic { private final DiagnosticInfo diagnosticInfo; - private Object[] args; + private final Object[] args; - private RuntimeDiagnosticLocation location; + private final RuntimeDiagnosticLocation location; public RuntimeDiagnostic(DiagnosticInfo diagnosticInfo, String location, Object[] args) { this.diagnosticInfo = diagnosticInfo; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/diagnostics/RuntimeDiagnosticLocation.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/diagnostics/RuntimeDiagnosticLocation.java index 10e55ad8220b..243ae95b2fb5 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/diagnostics/RuntimeDiagnosticLocation.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/diagnostics/RuntimeDiagnosticLocation.java @@ -28,7 +28,7 @@ */ public class RuntimeDiagnosticLocation implements Location { - private String location; + private final String location; public RuntimeDiagnosticLocation(String location) { this.location = location; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/diagnostics/RuntimeDiagnosticLog.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/diagnostics/RuntimeDiagnosticLog.java index 7d0e814ceaff..7b08579ffd2e 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/diagnostics/RuntimeDiagnosticLog.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/diagnostics/RuntimeDiagnosticLog.java @@ -32,7 +32,7 @@ */ public class RuntimeDiagnosticLog { - private List diagnosticList = new LinkedList<>(); + private final List diagnosticList = new LinkedList<>(); private int errorCount = 0; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/errors/ErrorCodes.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/errors/ErrorCodes.java index 96c0f7dbfe3e..6f09352514d7 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/errors/ErrorCodes.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/errors/ErrorCodes.java @@ -156,8 +156,9 @@ public enum ErrorCodes implements DiagnosticCode { CONFIG_UNUSED_ENV_VARS("config.env.unused.vars", "RUNTIME_0126"), CONFIG_ENV_VAR_NAME_AMBIGUITY("config.env.variable.name.ambiguity", "RUNTIME_0127"), NO_MESSAGE_ERROR("no.worker.message.received", "RUNTIME_0128"), - INVALID_METHOD_CALL("invalid.method.call", "RUNTIME_0129"), - INVALID_FUNCTION_INVOCATION("invalid.function.invocation.call", "RUNTIME_0130"), + FUNCTION_ALREADY_CALLED("function.already.called", "RUNTIME_0129"), + INVALID_FUNCTION_INVOCATION_BEFORE_MODULE_INIT("invalid.function.call.before.module.init", "RUNTIME_0130"), + INVALID_TUPLE_MEMBER_SIZE("invalid.tuple.member.size", "RUNTIME_0131"), // transaction recovery errors TRANSACTION_INVALID_CHECKPOINT_VALUE("transaction.invalid.checkpoint.value", "RUNTIME_0131"), diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/errors/ErrorHelper.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/errors/ErrorHelper.java index ae1fa77d9947..f28cbc6167a5 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/errors/ErrorHelper.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/errors/ErrorHelper.java @@ -36,7 +36,7 @@ * * @since 2201.7.0 */ -public class ErrorHelper { +public final class ErrorHelper { private static final ResourceBundle messageBundle = ResourceBundle.getBundle("MessagesBundle", Locale.getDefault()); private static final BString ERROR_MESSAGE_FIELD = StringUtils.fromString("message"); @@ -53,7 +53,8 @@ public static BError getRuntimeException(BString reason, ErrorCodes errorCodes, MappingInitialValueEntry[] initialValues = new MappingInitialValueEntry[1]; initialValues[0] = new MappingInitialValueEntry.KeyValueEntry(ERROR_MESSAGE_FIELD, StringUtils .fromString(MessageFormat.format(messageBundle.getString(errorCodes.messageKey()), params))); - MapValueImpl errorDetail = new MapValueImpl(PredefinedTypes.TYPE_ERROR_DETAIL, initialValues); + MapValueImpl errorDetail = + new MapValueImpl<>(PredefinedTypes.TYPE_ERROR_DETAIL, initialValues); return ErrorCreator.createError(reason, errorDetail); } @@ -67,7 +68,7 @@ public static BMap getErrorDetails(ErrorCodes errorCodes, Objec initialValues[0] = new MappingInitialValueEntry.KeyValueEntry(ERROR_MESSAGE_FIELD, StringUtils.fromString(MessageFormat.format(messageBundle.getString( errorCodes.messageKey()), params))); - return new MapValueImpl(PredefinedTypes.TYPE_ERROR_DETAIL, initialValues); + return new MapValueImpl<>(PredefinedTypes.TYPE_ERROR_DETAIL, initialValues); } public static BString getErrorMessage(String messageFormat, Object... params) { @@ -97,10 +98,10 @@ public static void handleXMLException(String operation, Throwable e) { } private static boolean isBErrorWithMessageDetail(Throwable e) { - if (!(e instanceof BError)) { + if (!(e instanceof BError error)) { return false; } - return hasMessageDetail((BError) e); + return hasMessageDetail(error); } public static boolean hasMessageDetail(BError bError) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/errors/ErrorReasons.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/errors/ErrorReasons.java index ed8e8f0540f5..ef56be56c717 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/errors/ErrorReasons.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/errors/ErrorReasons.java @@ -35,7 +35,7 @@ * * @since 0.990.0 */ -public class ErrorReasons { +public final class ErrorReasons { private ErrorReasons() {} diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/launch/LaunchUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/launch/LaunchUtils.java index 733a5c065ef2..d7c8f54b025b 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/launch/LaunchUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/launch/LaunchUtils.java @@ -32,14 +32,12 @@ import io.ballerina.runtime.internal.diagnostics.RuntimeDiagnosticLog; import io.ballerina.runtime.internal.troubleshoot.StrandDump; import io.ballerina.runtime.internal.util.RuntimeUtils; -import org.apache.commons.lang3.ArrayUtils; import sun.misc.Signal; import java.io.File; import java.io.PrintStream; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -60,7 +58,7 @@ * * @since 1.0 */ -public class LaunchUtils { +public final class LaunchUtils { private static final PrintStream outStream = System.out; @@ -96,11 +94,16 @@ public static void stopListeners(boolean isService) { public static void addModuleConfigData(Map configurationData, Module m, VariableKey[] variableKeys) { - VariableKey[] keys = configurationData.put(m, variableKeys); - if (keys == null) { - return; + VariableKey[] currKeys = configurationData.get(m); + VariableKey[] mergedKeyArray; + if (currKeys == null) { + mergedKeyArray = variableKeys; + } else { + mergedKeyArray = new VariableKey[currKeys.length + variableKeys.length]; + System.arraycopy(currKeys, 0, mergedKeyArray, 0, currKeys.length); + System.arraycopy(variableKeys, 0, mergedKeyArray, currKeys.length, variableKeys.length); } - configurationData.put(m, ArrayUtils.addAll(keys, variableKeys)); + configurationData.put(m, mergedKeyArray); } public static void initConfigurableVariables(Module rootModule, Map configurationData, @@ -143,7 +146,7 @@ private static String populateConfigDetails(List paths, Map paths, Map readRegChars(); + case BACK_SLASH_TOKEN -> readRegEscapeChar(); + case OPEN_BRACKET_TOKEN -> readRegCharacterClass(); + case OPEN_PAREN_TOKEN -> readRegCapturingGroups(); + // Here the token is a syntax char, which is invalid. Syntax char tokens should be + // proceeded by backslashes. + default -> throw ErrorCreator.createError(ErrorHelper.getErrorMessage( + ErrorCodes.REGEXP_MISSING_BACKSLASH.messageKey(), nextToken.value)); + }; RegExpQuantifier quantifier = readOptionalQuantifier(); if (quantifier == null) { @@ -164,31 +154,30 @@ private RegExpLiteralCharOrEscape readRegEscapeChar() { private String readRegEscape(Token backSlash) { Token nextToken = peek(); - switch (nextToken.kind) { - case RE_PROPERTY: - return readRegUnicodePropertyEscape(backSlash.value); - case BITWISE_XOR_TOKEN: - case DOLLAR_TOKEN: - case BACK_SLASH_TOKEN: - case DOT_TOKEN: - case ASTERISK_TOKEN: - case PLUS_TOKEN: - case QUESTION_MARK_TOKEN: - case OPEN_PAREN_TOKEN: - case CLOSE_PAREN_TOKEN: - case OPEN_BRACKET_TOKEN: - case CLOSE_BRACKET_TOKEN: - case OPEN_BRACE_TOKEN: - case CLOSE_BRACE_TOKEN: - case PIPE_TOKEN: - return readRegQuoteEscape(backSlash.value); - default: + return switch (nextToken.kind) { + case RE_PROPERTY -> readRegUnicodePropertyEscape(backSlash.value); + case BITWISE_XOR_TOKEN, + DOLLAR_TOKEN, + BACK_SLASH_TOKEN, + DOT_TOKEN, + ASTERISK_TOKEN, + PLUS_TOKEN, + QUESTION_MARK_TOKEN, + OPEN_PAREN_TOKEN, + CLOSE_PAREN_TOKEN, + OPEN_BRACKET_TOKEN, + CLOSE_BRACKET_TOKEN, + OPEN_BRACE_TOKEN, + CLOSE_BRACE_TOKEN, + PIPE_TOKEN -> readRegQuoteEscape(backSlash.value); + default -> { if (isReSimpleCharClassCode(nextToken)) { - return readRegSimpleCharClassEscape(backSlash.value); + yield readRegSimpleCharClassEscape(backSlash.value); } throw ErrorCreator.createError(ErrorHelper.getErrorMessage( ErrorCodes.REGEXP_INVALID_CHAR_AFTER_BACKSLASH.messageKey(), nextToken.value)); - } + } + }; } /** @@ -434,15 +423,10 @@ private String readCharacterClassEnd() { private RegExpQuantifier readOptionalQuantifier() { Token nextToken = peek(); - switch (nextToken.kind) { - case QUESTION_MARK_TOKEN: - case ASTERISK_TOKEN: - case PLUS_TOKEN: - case OPEN_BRACE_TOKEN: - return readReQuantifier(); - default: - return null; - } + return switch (nextToken.kind) { + case QUESTION_MARK_TOKEN, ASTERISK_TOKEN, PLUS_TOKEN, OPEN_BRACE_TOKEN -> readReQuantifier(); + default -> null; + }; } private RegExpQuantifier readReQuantifier() { @@ -562,45 +546,31 @@ private String readCloseParenthesis() { } private boolean isEndOfReDisjunction(TokenKind kind) { - switch (kind) { - case EOF_TOKEN: - case CLOSE_PAREN_TOKEN: - return true; - default: - return false; - } + return switch (kind) { + case EOF_TOKEN, CLOSE_PAREN_TOKEN -> true; + default -> false; + }; } private boolean isEndOfReSequence(TokenKind kind) { - switch (kind) { - case EOF_TOKEN: - case PIPE_TOKEN: - case CLOSE_PAREN_TOKEN: - return true; - default: - return false; - } + return switch (kind) { + case EOF_TOKEN, PIPE_TOKEN, CLOSE_PAREN_TOKEN -> true; + default -> false; + }; } private boolean isCharacterClassEnd(TokenKind kind) { - switch (kind) { - case EOF_TOKEN: - case CLOSE_BRACKET_TOKEN: - return true; - default: - return false; - } + return switch (kind) { + case EOF_TOKEN, CLOSE_BRACKET_TOKEN -> true; + default -> false; + }; } private boolean isReCharSetLiteralChar(String tokenText) { - switch (tokenText) { - case "\\": - case "-": - case "]": - return false; - default: - return true; - } + return switch (tokenText) { + case "\\", "-", "]" -> false; + default -> true; + }; } private boolean isEndOfFlagExpression(TokenKind kind) { @@ -612,15 +582,11 @@ private boolean isEndOfReFlags(TokenKind kind) { } private boolean isEndOfDigits(TokenKind kind, boolean isLeastDigits) { - switch (kind) { - case CLOSE_BRACE_TOKEN: - case EOF_TOKEN: - return true; - case COMMA_TOKEN: - return isLeastDigits; - default: - return false; - } + return switch (kind) { + case CLOSE_BRACE_TOKEN, EOF_TOKEN -> true; + case COMMA_TOKEN -> isLeastDigits; + default -> false; + }; } static boolean isIncorrectCharRange(String lhsValue, String rhsValue) { @@ -634,32 +600,20 @@ static boolean isReSimpleCharClassCode(Token token) { if (token.kind != TokenKind.RE_LITERAL_CHAR) { return false; } - switch (token.value) { - case "d": - case "D": - case "s": - case "S": - case "w": - case "W": - return true; - default: - return false; - } + return switch (token.value) { + case "d", "D", "s", "S", "w", "W" -> true; + default -> false; + }; } static boolean isReFlag(Token nextToken) { if (nextToken.kind != TokenKind.RE_LITERAL_CHAR) { return false; } - switch (nextToken.value) { - case "m": - case "s": - case "i": - case "x": - return true; - default: - return false; - } + return switch (nextToken.value) { + case "m", "s", "i", "x" -> true; + default -> false; + }; } private BString getErrorMsg(Token nextToken) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/regexp/TreeTraverser.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/regexp/TreeTraverser.java index 599be7f5775c..d2ffe5841a35 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/regexp/TreeTraverser.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/regexp/TreeTraverser.java @@ -30,9 +30,9 @@ */ public class TreeTraverser { - private CharReader reader; + private final CharReader reader; private ParserMode mode; - private ArrayDeque modeStack = new ArrayDeque<>(); + private final ArrayDeque modeStack = new ArrayDeque<>(); public TreeTraverser(CharReader charReader) { this.reader = charReader; @@ -41,18 +41,14 @@ public TreeTraverser(CharReader charReader) { } public Token nextToken() { - switch (this.mode) { - case RE_DISJUNCTION: - return readTokenInReDisjunction(); - case RE_UNICODE_PROP_ESCAPE: - case RE_UNICODE_GENERAL_CATEGORY_NAME: - return readTokenInReUnicodePropertyEscape(); - case RE_UNICODE_PROPERTY_VALUE: - return readTokenInReUnicodePropertyValue(); - default: - // Should not reach here. - return null; - } + return switch (this.mode) { + case RE_DISJUNCTION -> readTokenInReDisjunction(); + case RE_UNICODE_PROP_ESCAPE, + RE_UNICODE_GENERAL_CATEGORY_NAME -> readTokenInReUnicodePropertyEscape(); + case RE_UNICODE_PROPERTY_VALUE -> readTokenInReUnicodePropertyValue(); + // Should not reach here. + default -> null; + }; } /** @@ -81,47 +77,31 @@ private Token readTokenInReDisjunction() { int nextChar = peek(); this.reader.advance(); - switch (nextChar) { - case Terminals.BITWISE_XOR: - return getRegExpToken(TokenKind.BITWISE_XOR_TOKEN); - case Terminals.DOLLAR: - return getRegExpToken(TokenKind.DOLLAR_TOKEN); - case Terminals.DOT: - return getRegExpToken(TokenKind.DOT_TOKEN); - case Terminals.ASTERISK: - return getRegExpToken(TokenKind.ASTERISK_TOKEN); - case Terminals.PLUS: - return getRegExpToken(TokenKind.PLUS_TOKEN); - case Terminals.QUESTION_MARK: - return getRegExpToken(TokenKind.QUESTION_MARK_TOKEN); - case Terminals.BACKSLASH: - return processEscape(); - case Terminals.OPEN_BRACKET: - return getRegExpToken(TokenKind.OPEN_BRACKET_TOKEN); - case Terminals.CLOSE_BRACKET: - return getRegExpToken(TokenKind.CLOSE_BRACKET_TOKEN); - case Terminals.OPEN_BRACE: - return getRegExpToken(TokenKind.OPEN_BRACE_TOKEN); - case Terminals.CLOSE_BRACE: - return getRegExpToken(TokenKind.CLOSE_BRACE_TOKEN); - case Terminals.OPEN_PARENTHESIS: - return getRegExpToken(TokenKind.OPEN_PAREN_TOKEN); - case Terminals.CLOSE_PARENTHESIS: - return getRegExpToken(TokenKind.CLOSE_PAREN_TOKEN); - case Terminals.COMMA: - return getRegExpToken(TokenKind.COMMA_TOKEN); - case Terminals.MINUS: - return getRegExpToken(TokenKind.MINUS_TOKEN); - case Terminals.COLON: - return getRegExpToken(TokenKind.COLON_TOKEN); - case Terminals.PIPE: - return getRegExpToken(TokenKind.PIPE_TOKEN); - default: + return switch (nextChar) { + case Terminals.BITWISE_XOR -> getRegExpToken(TokenKind.BITWISE_XOR_TOKEN); + case Terminals.DOLLAR -> getRegExpToken(TokenKind.DOLLAR_TOKEN); + case Terminals.DOT -> getRegExpToken(TokenKind.DOT_TOKEN); + case Terminals.ASTERISK -> getRegExpToken(TokenKind.ASTERISK_TOKEN); + case Terminals.PLUS -> getRegExpToken(TokenKind.PLUS_TOKEN); + case Terminals.QUESTION_MARK -> getRegExpToken(TokenKind.QUESTION_MARK_TOKEN); + case Terminals.BACKSLASH -> processEscape(); + case Terminals.OPEN_BRACKET -> getRegExpToken(TokenKind.OPEN_BRACKET_TOKEN); + case Terminals.CLOSE_BRACKET -> getRegExpToken(TokenKind.CLOSE_BRACKET_TOKEN); + case Terminals.OPEN_BRACE -> getRegExpToken(TokenKind.OPEN_BRACE_TOKEN); + case Terminals.CLOSE_BRACE -> getRegExpToken(TokenKind.CLOSE_BRACE_TOKEN); + case Terminals.OPEN_PARENTHESIS -> getRegExpToken(TokenKind.OPEN_PAREN_TOKEN); + case Terminals.CLOSE_PARENTHESIS -> getRegExpToken(TokenKind.CLOSE_PAREN_TOKEN); + case Terminals.COMMA -> getRegExpToken(TokenKind.COMMA_TOKEN); + case Terminals.MINUS -> getRegExpToken(TokenKind.MINUS_TOKEN); + case Terminals.COLON -> getRegExpToken(TokenKind.COLON_TOKEN); + case Terminals.PIPE -> getRegExpToken(TokenKind.PIPE_TOKEN); + default -> { if (isDigit(nextChar)) { - return getRegExpText(TokenKind.DIGIT); + yield getRegExpText(TokenKind.DIGIT); } - return getRegExpText(TokenKind.RE_LITERAL_CHAR); - } + yield getRegExpText(TokenKind.RE_LITERAL_CHAR); + } + }; } /** @@ -496,25 +476,10 @@ public void endMode() { * @return true, if the character is ReSyntaxChar. false otherwise. */ private static boolean isReSyntaxChar(int c) { - switch (c) { - case '^': - case '$': - case '\\': - case '.': - case '*': - case '+': - case '?': - case '(': - case ')': - case '[': - case ']': - case '{': - case '}': - case '|': - return true; - default: - return false; - } + return switch (c) { + case '^', '$', '\\', '.', '*', '+', '?', '(', ')', '[', ']', '{', '}', '|' -> true; + default -> false; + }; } /** @@ -528,17 +493,10 @@ private static boolean isReSyntaxChar(int c) { * @return true, if the character is ReSimpleCharClassCode. false otherwise. */ private static boolean isReSimpleCharClassCode(int c) { - switch (c) { - case 'd': - case 'D': - case 's': - case 'S': - case 'w': - case 'W': - return true; - default: - return false; - } + return switch (c) { + case 'd', 'D', 's', 'S', 'w', 'W' -> true; + default -> false; + }; } private static boolean isHexDigit(int c) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/AsyncFunctionCallback.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/AsyncFunctionCallback.java index 1071e91cac47..e2efb600c53d 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/AsyncFunctionCallback.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/AsyncFunctionCallback.java @@ -30,7 +30,7 @@ public abstract class AsyncFunctionCallback implements Callback { private FutureValue future; - private Strand strand; + private final Strand strand; public AsyncFunctionCallback(Strand strand) { this.strand = strand; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/AsyncUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/AsyncUtils.java index ead9ae63867b..945f60e47513 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/AsyncUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/AsyncUtils.java @@ -45,6 +45,7 @@ import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; @@ -52,7 +53,7 @@ /** * Util functions for async invocations. */ -public class AsyncUtils { +public final class AsyncUtils { /** * Block the current strand to execute asynchronously. @@ -80,7 +81,7 @@ public static CompletableFuture markAsync() { * @param scheduler The scheduler for invoking functions * @return Future Value */ - public static FutureValue invokeFunctionPointerAsync(BFunctionPointer func, String strandName, + public static FutureValue invokeFunctionPointerAsync(BFunctionPointer func, String strandName, StrandMetadata metadata, Object[] args, Function resultHandleFunction, Scheduler scheduler) { @@ -129,7 +130,7 @@ public void notifyFailure(BError error) { * @param returnValueSupplier Suppler used to set the final return value for the parent function invocation. * @param scheduler The scheduler for invoking functions */ - public static void invokeFunctionPointerAsyncIteratively(BFunctionPointer func, String strandName, + public static void invokeFunctionPointerAsyncIteratively(BFunctionPointer func, String strandName, StrandMetadata metadata, int noOfIterations, Supplier argsSupplier, Consumer futureResultConsumer, @@ -215,7 +216,7 @@ private static void callDefaultValueFunction(Scheduler scheduler, Callback callb List argsWithDefaultValues, Parameter parameter) { String funcName = parameter.defaultFunctionName; - Function defaultFunc = o -> valueCreator.call((Strand) (((Object[]) o)[0]), funcName, + Function defaultFunc = o -> valueCreator.call((Strand) (((Object[]) o)[0]), funcName, argsWithDefaultValues.toArray()); Callback defaultFunctionCallback = new Callback() { @Override @@ -253,7 +254,7 @@ private static MethodType getObjectMethodType(String methodName, ObjectType obje return methodTypesMap.get(methodName); } - private static void scheduleNextFunction(BFunctionPointer func, BFunctionType funcType, Strand parent, + private static void scheduleNextFunction(BFunctionPointer func, BFunctionType funcType, Strand parent, String strandName, StrandMetadata metadata, int noOfIterations, AtomicInteger callCount, Supplier argsSupplier, Consumer futureResultConsumer, @@ -288,7 +289,7 @@ public void notifyFailure(BError error) { }, argsSupplier.get()); } - private static void invokeFunctionPointerAsync(BFunctionPointer func, Strand parent, + private static void invokeFunctionPointerAsync(BFunctionPointer func, Strand parent, FutureValue future, Object[] args, AsyncFunctionCallback callback, Scheduler scheduler) { future.callback = callback; @@ -312,7 +313,7 @@ private static void handleRuntimeErrors(Strand parent, BError error) { parent.scheduler.unblockStrand(parent); } - private static class Unblocker implements java.util.function.BiConsumer { + private static class Unblocker implements BiConsumer { private final Strand strand; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/RuntimeRegistry.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/RuntimeRegistry.java index c490d9cf7efd..1b916ae629df 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/RuntimeRegistry.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/RuntimeRegistry.java @@ -26,10 +26,11 @@ import io.ballerina.runtime.internal.values.FutureValue; import java.io.PrintStream; +import java.util.Deque; import java.util.Iterator; import java.util.Set; -import java.util.Stack; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedDeque; import java.util.function.Function; import static io.ballerina.runtime.api.values.BError.ERROR_PRINT_PREFIX; @@ -43,7 +44,7 @@ public class RuntimeRegistry { private final Scheduler scheduler; private final Set listenerSet = ConcurrentHashMap.newKeySet(); - private final Stack> stopHandlerStack = new Stack<>(); + private final Deque> stopHandlerStack = new ConcurrentLinkedDeque<>(); private static final PrintStream outStream = System.err; @@ -63,7 +64,7 @@ public synchronized void deregisterListener(BObject listener) { } } - public synchronized void registerStopHandler(BFunctionPointer stopHandler) { + public synchronized void registerStopHandler(BFunctionPointer stopHandler) { stopHandlerStack.push(stopHandler); } @@ -78,7 +79,7 @@ private synchronized void invokeListenerGracefulStop(Strand strand, Scheduler sc if (iterator.hasNext()) { ListenerCallback callback = new ListenerCallback(strand, scheduler, iterator); BObject listener = iterator.next(); - Function func = o -> listener.call((Strand) ((Object[]) o)[0], "gracefulStop"); + Function func = o -> listener.call((Strand) (o)[0], "gracefulStop"); scheduler.schedule(new Object[1], func, null, callback, null, null, null, strand.getMetadata()); } else { @@ -90,7 +91,7 @@ private synchronized void invokeStopHandlerFunction(Strand strand, Scheduler sch if (stopHandlerStack.isEmpty()) { return; } - BFunctionPointer bFunctionPointer = stopHandlerStack.pop(); + BFunctionPointer bFunctionPointer = stopHandlerStack.pop(); StopHandlerCallback callback = new StopHandlerCallback(strand, scheduler); final FutureValue future = scheduler.createFuture(strand, callback, null, ((BFunctionType) TypeUtils.getImpliedType(bFunctionPointer.getType())).retType, null, diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/Scheduler.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/Scheduler.java index 112832b002bf..a2d081f95ff9 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/Scheduler.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/Scheduler.java @@ -54,7 +54,7 @@ */ public class Scheduler { - private static final PrintStream err = System.err; + private static final PrintStream ERR = System.err; /** * Scheduler does not get killed if the immortal value is true. Specific to services. @@ -66,13 +66,13 @@ public class Scheduler { */ private final BlockingQueue runnableList = new LinkedBlockingDeque<>(); - private static final ThreadLocal strandHolder = ThreadLocal.withInitial(StrandHolder::new); - private static final ConcurrentHashMap currentStrands = new ConcurrentHashMap<>(); + private static final ThreadLocal STRAND_HOLDER = ThreadLocal.withInitial(StrandHolder::new); + private static final ConcurrentHashMap CURRENT_STRANDS = new ConcurrentHashMap<>(); private final Strand previousStrand; private final AtomicInteger totalStrands = new AtomicInteger(); - private static String poolSizeConf = System.getenv(RuntimeConstants.BALLERINA_MAX_POOL_SIZE_ENV_VAR); + private static final String POOL_SIZE_CONF = System.getenv(RuntimeConstants.BALLERINA_MAX_POOL_SIZE_ENV_VAR); /** * This can be changed by setting the BALLERINA_MAX_POOL_SIZE system variable. @@ -84,7 +84,7 @@ public class Scheduler { private Semaphore mainBlockSem; private final RuntimeRegistry runtimeRegistry; - private AtomicReference objectGroup = new AtomicReference<>(); + private final AtomicReference objectGroup = new AtomicReference<>(); private static Strand daemonStrand = null; public static void setDaemonStrand(Strand strand) { @@ -103,13 +103,13 @@ public Scheduler(int numThreads, boolean immortal) { this.numThreads = numThreads; this.immortal = immortal; this.runtimeRegistry = new RuntimeRegistry(this); - this.previousStrand = numThreads == 1 ? strandHolder.get().strand : null; + this.previousStrand = numThreads == 1 ? STRAND_HOLDER.get().strand : null; ItemGroup group = new ItemGroup(); objectGroup.set(group); } public static Strand getStrand() { - Strand strand = strandHolder.get().strand; + Strand strand = STRAND_HOLDER.get().strand; if (strand == null) { throw new IllegalStateException("strand is not accessible from non-strand-worker threads"); } @@ -118,11 +118,11 @@ public static Strand getStrand() { public static Strand getStrandNoException() { // issue #22871 is opened to fix this - return strandHolder.get().strand; + return STRAND_HOLDER.get().strand; } public static Map getCurrentStrands() { - return new HashMap<>(currentStrands); + return new HashMap<>(CURRENT_STRANDS); } /** @@ -136,12 +136,14 @@ public static Map getCurrentStrands() { * @param metadata meta data of new strand * @return {@link FutureValue} reference to the given function pointer invocation. */ - public FutureValue scheduleFunction(Object[] params, BFunctionPointer fp, Strand parent, Type returnType, + public FutureValue scheduleFunction(Object[] params, + BFunctionPointer fp, Strand parent, Type returnType, String strandName, StrandMetadata metadata) { return schedule(params, fp.getFunction(), parent, null, null, returnType, strandName, metadata); } - public FutureValue scheduleFunction(Object[] params, BFunctionPointer fp, Strand parent, Type returnType, + public FutureValue scheduleFunction(Object[] params, + BFunctionPointer fp, Strand parent, Type returnType, String strandName, StrandMetadata metadata , Callback callback) { return schedule(params, fp.getFunction(), parent, callback, null, returnType, strandName, metadata); } @@ -157,13 +159,14 @@ public FutureValue scheduleFunction(Object[] params, BFunctionPointer fp, * @param metadata meta data of new strand * @return {@link FutureValue} reference to the given function invocation. */ - public FutureValue scheduleLocal(Object[] params, BFunctionPointer fp, Strand parent, Type returnType, + public FutureValue scheduleLocal(Object[] params, BFunctionPointer fp, Strand parent, Type returnType, String strandName, StrandMetadata metadata) { FutureValue future = createFuture(parent, null, null, returnType, strandName, metadata); return scheduleLocal(params, fp, parent, future); } - public FutureValue scheduleLocal(Object[] params, BFunctionPointer fp, Strand parent, FutureValue future) { + public FutureValue scheduleLocal(Object[] params, BFunctionPointer fp, + Strand parent, FutureValue future) { params[0] = future.strand; SchedulerItem item = new SchedulerItem(fp.getFunction(), params, future); future.strand.schedulerItem = item; @@ -173,14 +176,15 @@ public FutureValue scheduleLocal(Object[] params, BFunctionPointer fp, Str return future; } - public FutureValue scheduleToObjectGroup(Object[] params, Function function, Strand parent, + public FutureValue scheduleToObjectGroup(Object[] params, Function function, Strand parent, Callback callback, Map properties, Type returnType, String strandName, StrandMetadata metadata) { FutureValue future = createFuture(parent, callback, properties, returnType, strandName, metadata); return scheduleToObjectGroup(params, function, future); } - public FutureValue scheduleToObjectGroup(Object[] params, Function function, FutureValue future) { + public FutureValue scheduleToObjectGroup(Object[] params, Function function, + FutureValue future) { params[0] = future.strand; SchedulerItem item = new SchedulerItem(function, params, future); future.strand.schedulerItem = item; @@ -204,7 +208,7 @@ public FutureValue scheduleToObjectGroup(Object[] params, Function function, Fut * @param metadata meta data of new strand * @return Reference to the scheduled task */ - public FutureValue schedule(Object[] params, Function function, Strand parent, Callback callback, + public FutureValue schedule(Object[] params, Function function, Strand parent, Callback callback, Map properties, Type returnType, String strandName, StrandMetadata metadata) { FutureValue future = createFuture(parent, callback, properties, returnType, strandName, metadata); @@ -222,13 +226,13 @@ public FutureValue schedule(Object[] params, Function function, Strand parent, C * @param metadata meta data of new strand * @return Reference to the scheduled task */ - public FutureValue schedule(Object[] params, Function function, Strand parent, Callback callback, + public FutureValue schedule(Object[] params, Function function, Strand parent, Callback callback, String strandName, StrandMetadata metadata) { FutureValue future = createFuture(parent, callback, null, PredefinedTypes.TYPE_NULL, strandName, metadata); return schedule(params, function, future); } - public FutureValue schedule(Object[] params, Function function, FutureValue future) { + public FutureValue schedule(Object[] params, Function function, FutureValue future) { params[0] = future.strand; SchedulerItem item = new SchedulerItem(function, params, future); future.strand.schedulerItem = item; @@ -252,7 +256,7 @@ public FutureValue schedule(Object[] params, Function function, FutureValue futu * @return Reference to the scheduled task */ @Deprecated - public FutureValue schedule(Object[] params, Consumer consumer, Strand parent, Callback callback, + public FutureValue schedule(Object[] params, Consumer consumer, Strand parent, Callback callback, String strandName, StrandMetadata metadata) { FutureValue future = createFuture(parent, callback, null, PredefinedTypes.TYPE_NULL, strandName, metadata); params[0] = future.strand; @@ -316,7 +320,7 @@ private void run() { item = group.get(); try { - strandHolder.get().strand = item.future.strand; + STRAND_HOLDER.get().strand = item.future.strand; result = item.execute(); } catch (Throwable e) { panic = createError(e); @@ -331,11 +335,11 @@ private void run() { RuntimeUtils.printCrashLog(panic); } } finally { - strandHolder.get().strand = previousStrand; + STRAND_HOLDER.get().strand = previousStrand; } postProcess(item, result, panic); group.lock(); - if ((isItemsEmpty = group.items.empty())) { + if ((isItemsEmpty = group.items.isEmpty())) { group.scheduled.set(false); } group.unlock(); @@ -458,7 +462,7 @@ private void cleanUp(Strand justCompleted) { justCompleted.frames = null; justCompleted.waitingContexts = null; - currentStrands.remove(justCompleted.getId()); + CURRENT_STRANDS.remove(justCompleted.getId()); //TODO: more cleanup , eg channels } @@ -507,7 +511,7 @@ public FutureValue createFuture(Strand parent, Callback callback, Map function; + private final Object[] params; final FutureValue future; boolean parked; - public SchedulerItem(Function function, Object[] params, FutureValue future) { + public SchedulerItem(Function function, Object[] params, FutureValue future) { this.future = future; this.function = function; this.params = params; } @Deprecated - public SchedulerItem(Consumer consumer, Object[] params, FutureValue future) { + public SchedulerItem(Consumer consumer, Object[] params, FutureValue future) { this.future = future; this.function = val -> { consumer.accept(val); diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/State.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/State.java index 57f18630fbb7..fa88e1592eb7 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/State.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/State.java @@ -1,4 +1,4 @@ - /* +/* * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, @@ -17,25 +17,25 @@ */ package io.ballerina.runtime.internal.scheduling; - /** - * Maintains the Strand state. - * - * @since 1.0.0 - */ - public enum State { - RUNNABLE(1), - YIELD(1 << 1), - BLOCK_AND_YIELD(YIELD.status | (1 << 2)), - BLOCK_ON_AND_YIELD(BLOCK_AND_YIELD.status | (1 << 3)), - DONE(1 << 4); +/** + * Maintains the Strand state. + * + * @since 1.0.0 + */ +public enum State { + RUNNABLE(1), + YIELD(1 << 1), + BLOCK_AND_YIELD(YIELD.status | (1 << 2)), + BLOCK_ON_AND_YIELD(BLOCK_AND_YIELD.status | (1 << 3)), + DONE(1 << 4); - private int status; + private final int status; - public int getStatus() { - return status; - } + public int getStatus() { + return status; + } - State(int status) { - this.status = status; - } - } + State(int status) { + this.status = status; + } +} diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/Strand.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/Strand.java index e421bbf9d0b2..0e9e972752a4 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/Strand.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/Strand.java @@ -94,6 +94,14 @@ public class Strand { public BMap workerReceiveMap = null; public int channelCount = 0; + public Strand() { + this.id = -1; + this.strandLock = null; + this.name = null; + this.metadata = null; + this.state = RUNNABLE; + } + public Strand(String name, StrandMetadata metadata, Scheduler scheduler, Strand parent, Map properties) { this.id = nextStrandId.incrementAndGet(); @@ -156,11 +164,10 @@ private TransactionLocalContext createTrxContextBranch(TransactionLocalContext c } public void handleChannelError(ChannelDetails[] channels, ErrorValue error) { - for (int i = 0; i < channels.length; i++) { - ChannelDetails channelDetails = channels[i]; + for (ChannelDetails channelDetails : channels) { WorkerDataChannel channel = getWorkerDataChannel(channelDetails); - if (channels[i].send) { + if (channelDetails.send) { channel.setSendError(error); } else { channel.setReceiveError(error); diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/SyncCallback.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/SyncCallback.java new file mode 100644 index 000000000000..34b6987c7c08 --- /dev/null +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/SyncCallback.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://wso2.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.ballerina.runtime.internal.scheduling; + +import io.ballerina.runtime.api.async.Callback; +import io.ballerina.runtime.api.values.BError; + +import java.util.concurrent.CountDownLatch; + +/** + * This class used to handle ballerina function invocation synchronously. + * + * @since 2201.9.1 + */ +public class SyncCallback implements Callback { + + public CountDownLatch latch; + public BError initError; + + public SyncCallback(CountDownLatch latch) { + this.latch = latch; + } + + @Override + public void notifySuccess(Object result) { + latch.countDown(); + } + + @Override + public void notifyFailure(BError error) { + latch.countDown(); + initError = error; + } +} diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/WaitAnyContext.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/WaitAnyContext.java index 4fa14cbda8fb..750d3540b4b4 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/WaitAnyContext.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/WaitAnyContext.java @@ -1,47 +1,47 @@ - /* - * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. 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.runtime.internal.scheduling; +/* + * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.runtime.internal.scheduling; - import io.ballerina.runtime.api.PredefinedTypes; - import io.ballerina.runtime.internal.TypeChecker; +import io.ballerina.runtime.api.PredefinedTypes; +import io.ballerina.runtime.internal.TypeChecker; - /** - * WaitContext for Wait for any action. - * - * @since 1.0.0 - */ - public class WaitAnyContext extends WaitContext { +/** + * WaitContext for Wait for any action. + * + * @since 1.0.0 + */ +public class WaitAnyContext extends WaitContext { - WaitAnyContext(SchedulerItem schedulerItem) { - super(schedulerItem); - } + WaitAnyContext(SchedulerItem schedulerItem) { + super(schedulerItem); + } - @Override - boolean handlePanic() { - waitCount.set(0); - return true; - } + @Override + boolean handlePanic() { + waitCount.set(0); + return true; + } - @Override - boolean waitCompleted(Object result) { - if (TypeChecker.checkIsType(result, PredefinedTypes.TYPE_ERROR)) { - return waitCount.decrementAndGet() == 0; - } - return true; - } - } + @Override + boolean waitCompleted(Object result) { + if (TypeChecker.checkIsType(result, PredefinedTypes.TYPE_ERROR)) { + return waitCount.decrementAndGet() == 0; + } + return true; + } +} diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/WaitContext.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/WaitContext.java index 2d691fa87f33..7fba62f2581b 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/WaitContext.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/WaitContext.java @@ -1,58 +1,57 @@ - /* - * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. 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.runtime.internal.scheduling; - - import java.util.concurrent.atomic.AtomicInteger; - import java.util.concurrent.locks.ReentrantLock; - - /** - * This context is shared among the strands to notify that a - * certain strand is waiting on another strand. - * - * @since 1.0.0 - */ - public abstract class WaitContext { - - SchedulerItem schedulerItem; - boolean runnable; - boolean completed; - boolean intermediate; - private final ReentrantLock contextLock; - AtomicInteger waitCount; - - - WaitContext(SchedulerItem schedulerItem) { - this.schedulerItem = schedulerItem; - this.contextLock = new ReentrantLock(); - this.waitCount = new AtomicInteger(); - this.intermediate = true; - - } - - void lock() { - this.contextLock.lock(); - } - - void unLock() { - this.contextLock.unlock(); - } - - abstract boolean handlePanic(); - - abstract boolean waitCompleted(Object result); - } +/* + * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.runtime.internal.scheduling; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; + +/** + * This context is shared among the strands to notify that a + * certain strand is waiting on another strand. + * + * @since 1.0.0 + */ +public abstract class WaitContext { + + SchedulerItem schedulerItem; + boolean runnable; + boolean completed; + boolean intermediate; + private final ReentrantLock contextLock; + AtomicInteger waitCount; + + + WaitContext(SchedulerItem schedulerItem) { + this.schedulerItem = schedulerItem; + this.contextLock = new ReentrantLock(); + this.waitCount = new AtomicInteger(); + this.intermediate = true; + } + + void lock() { + this.contextLock.lock(); + } + + void unLock() { + this.contextLock.unlock(); + } + + abstract boolean handlePanic(); + + abstract boolean waitCompleted(Object result); +} diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/WaitMultipleContext.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/WaitMultipleContext.java index 4cca0c544961..cee19b56db05 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/WaitMultipleContext.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/WaitMultipleContext.java @@ -1,41 +1,41 @@ - /* - * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. 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.runtime.internal.scheduling; +/* + * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.runtime.internal.scheduling; - /** - * WaitContext for Wait for all action. - * - * @since 1.0.0 - */ - public class WaitMultipleContext extends WaitContext { +/** + * WaitContext for Wait for all action. + * + * @since 1.0.0 + */ +public class WaitMultipleContext extends WaitContext { - WaitMultipleContext(SchedulerItem schedulerItem) { - super(schedulerItem); - } + WaitMultipleContext(SchedulerItem schedulerItem) { + super(schedulerItem); + } - @Override - boolean handlePanic() { - waitCount.set(0); - return true; - } + @Override + boolean handlePanic() { + waitCount.set(0); + return true; + } - @Override - boolean waitCompleted(Object result) { - return waitCount.decrementAndGet() == 0; - } - } + @Override + boolean waitCompleted(Object result) { + return waitCount.decrementAndGet() == 0; + } +} diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/WorkerUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/WorkerUtils.java index 0cbbf3cd5747..44f5091d9431 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/WorkerUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/scheduling/WorkerUtils.java @@ -1,46 +1,46 @@ - /* - * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. 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.runtime.internal.scheduling; +/* + * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.runtime.internal.scheduling; - import io.ballerina.runtime.api.PredefinedTypes; - import io.ballerina.runtime.internal.TypeChecker; - import io.ballerina.runtime.internal.values.ChannelDetails; - import io.ballerina.runtime.internal.values.ErrorValue; - import io.ballerina.runtime.internal.values.RefValue; +import io.ballerina.runtime.api.PredefinedTypes; +import io.ballerina.runtime.internal.TypeChecker; +import io.ballerina.runtime.internal.values.ChannelDetails; +import io.ballerina.runtime.internal.values.ErrorValue; +import io.ballerina.runtime.internal.values.RefValue; - /** - * Worker related utility methods for jBallerina runtime. - * - * @since 0.995.0 - */ - public class WorkerUtils { +/** + * Worker related utility methods for jBallerina runtime. + * + * @since 0.995.0 + */ +public final class WorkerUtils { - /** - * Notify worker data channels if this is a error return in a union type. - * @param value return value - * @param strand current strand - * @param channels worker date channels that current worker interacts - */ - public static void handleWorkerError(RefValue value, Strand strand, ChannelDetails[] channels) { - if (TypeChecker.checkIsType(value, PredefinedTypes.TYPE_ERROR)) { - strand.handleChannelError(channels, (ErrorValue) value); - } - } + /** + * Notify worker data channels if this is a error return in a union type. + * @param value return value + * @param strand current strand + * @param channels worker date channels that current worker interacts + */ + public static void handleWorkerError(RefValue value, Strand strand, ChannelDetails[] channels) { + if (TypeChecker.checkIsType(value, PredefinedTypes.TYPE_ERROR)) { + strand.handleChannelError(channels, (ErrorValue) value); + } + } - private WorkerUtils() {} - } + private WorkerUtils() {} +} diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/troubleshoot/StrandDump.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/troubleshoot/StrandDump.java index 74c1f0b7ba81..10b83c05004d 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/troubleshoot/StrandDump.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/troubleshoot/StrandDump.java @@ -35,7 +35,7 @@ * * @since 2201.2.0 */ -public class StrandDump { +public final class StrandDump { public static String getStrandDump() { Map availableStrands = Scheduler.getCurrentStrands(); diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BAnnotatableType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BAnnotatableType.java index 81c5d0dffe6e..a3ceb4253798 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BAnnotatableType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BAnnotatableType.java @@ -43,14 +43,17 @@ public void setAnnotations(BMap annotations) { this.annotations = annotations; } + @Override public BMap getAnnotations() { return (BMap) this.annotations.copy(new LinkedHashMap<>()); } + @Override public Object getAnnotation(BString key) { return this.annotations.get(key); } + @Override public Object getAnnotation(BString pkg, BString annotName) { return this.annotations.get(StringUtils.fromString(pkg.getValue() + ":" + annotName.getValue())); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BAnyType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BAnyType.java index 5d3f5d12ec45..6c9dfbbd046f 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BAnyType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BAnyType.java @@ -71,6 +71,7 @@ public int getTag() { return TypeTags.ANY_TAG; } + @Override public boolean isNilable() { return true; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BAnydataType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BAnydataType.java index 2f7b28c53605..7d006df8e080 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BAnydataType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BAnydataType.java @@ -74,6 +74,7 @@ public int getTag() { return TypeTags.ANYDATA_TAG; } + @Override public boolean isNilable() { return true; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BArrayType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BArrayType.java index 5b5344a730c1..d73fb58f5a82 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BArrayType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BArrayType.java @@ -101,6 +101,7 @@ private void setFlagsBasedOnElementType() { } } + @Override public Type getElementType() { return elementType; } @@ -127,8 +128,7 @@ public int hashCode() { @Override public boolean equals(Object obj) { - if (obj instanceof BArrayType) { - BArrayType other = (BArrayType) obj; + if (obj instanceof BArrayType other) { if (other.state == ArrayState.CLOSED && this.size != other.size) { return false; } @@ -160,14 +160,17 @@ public int getDimensions() { return this.dimensions; } + @Override public int getSize() { return size; } + @Override public boolean hasFillerValue() { return hasFillerValue; } + @Override public ArrayState getState() { return state; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BBooleanType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BBooleanType.java index 7eef2d162920..28031b69e41e 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BBooleanType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BBooleanType.java @@ -37,6 +37,7 @@ public BBooleanType(String typeName, Module pkg) { super(typeName, pkg, Boolean.class); } + @Override @SuppressWarnings("unchecked") public V getZeroValue() { return (V) Boolean.FALSE; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BErrorType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BErrorType.java index d01821fae7a9..59cf32500a3d 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BErrorType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BErrorType.java @@ -73,11 +73,10 @@ public void setDetailType(Type detailType) { @Override public boolean equals(Object obj) { - if (!super.equals(obj) || !(obj instanceof BErrorType)) { + if (!super.equals(obj) || !(obj instanceof BErrorType other)) { return false; } - BErrorType other = (BErrorType) obj; if (detailType == other.detailType) { return true; } @@ -90,6 +89,7 @@ public String getAnnotationKey() { return Utils.decodeIdentifier(typeName); } + @Override public Type getDetailType() { return detailType; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BField.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BField.java index 8aaf343c03c2..d1e0d4e1aa2e 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BField.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BField.java @@ -37,14 +37,17 @@ public BField(Type fieldType, String fieldName, long flags) { this.flags = flags; } + @Override public Type getFieldType() { return type; } + @Override public String getFieldName() { return name; } + @Override public long getFlags() { return flags; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BFiniteType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BFiniteType.java index 936f904164d8..3ca2ae443844 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BFiniteType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BFiniteType.java @@ -39,8 +39,8 @@ public class BFiniteType extends BType implements FiniteType { public Set valueSpace; - private int typeFlags; - private String originalName; + private final int typeFlags; + private final String originalName; public BFiniteType(String typeName) { this(typeName, new LinkedHashSet<>(), 0); @@ -141,10 +141,12 @@ public boolean isReadOnly() { return true; } + @Override public Set getValueSpace() { return valueSpace; } + @Override public int getTypeFlags() { return typeFlags; } @@ -182,10 +184,9 @@ public boolean equals(Object o) { if (this == o) { return true; } - if (!(o instanceof BFiniteType)) { + if (!(o instanceof BFiniteType that)) { return false; } - BFiniteType that = (BFiniteType) o; return this.valueSpace.size() == that.valueSpace.size() && this.valueSpace.containsAll(that.valueSpace); } } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BFunctionType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BFunctionType.java index 87dd2924dacd..9916e0ba4da4 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BFunctionType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BFunctionType.java @@ -81,6 +81,7 @@ public Type[] getParameterTypes() { return types; } + @Override public Type getReturnParameterType() { return retType; } @@ -114,15 +115,13 @@ public boolean equals(Object o) { if (this == o) { return true; } - if (!(o instanceof BFunctionType)) { + if (!(o instanceof BFunctionType that)) { return false; } if (!super.equals(o)) { return false; } - BFunctionType that = (BFunctionType) o; - boolean isSourceAnyFunction = SymbolFlags.isFlagOn(this.flags, SymbolFlags.ANY_FUNCTION); boolean isTargetAnyFunction = SymbolFlags.isFlagOn(that.flags, SymbolFlags.ANY_FUNCTION); @@ -179,9 +178,9 @@ public String toString() { if (parameters != null) { addParamListToString(parameters, stringRep); } - if (restType instanceof BArrayType) { + if (restType instanceof BArrayType bArrayType) { stringRep.append(","); - stringRep.append(((BArrayType) restType).getElementType().toString()); + stringRep.append(bArrayType.getElementType().toString()); stringRep.append("..."); } stringRep.append(")"); @@ -202,6 +201,7 @@ public boolean isReadOnly() { return true; } + @Override public Type getRestType() { return restType; } @@ -211,10 +211,12 @@ public Parameter[] getParameters() { return parameters; } + @Override public Type getReturnType() { return retType; } + @Override public long getFlags() { return flags; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BFutureType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BFutureType.java index 38e6bc656b04..df747fc1865c 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BFutureType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BFutureType.java @@ -70,7 +70,7 @@ public int getTag() { @Override public boolean equals(Object obj) { - if (!(obj instanceof BFutureType)) { + if (!(obj instanceof BFutureType other)) { return false; } @@ -78,7 +78,6 @@ public boolean equals(Object obj) { return false; } - BFutureType other = (BFutureType) obj; if (constraint == other.constraint) { return true; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BIntersectionType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BIntersectionType.java index 58c22226890a..c2112f4a4578 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BIntersectionType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BIntersectionType.java @@ -145,11 +145,10 @@ public boolean equals(Object o) { return true; } - if (!(o instanceof BIntersectionType)) { + if (!(o instanceof BIntersectionType that)) { return false; } - BIntersectionType that = (BIntersectionType) o; if (this.constituentTypes.size() != that.constituentTypes.size()) { return false; } @@ -202,6 +201,7 @@ public void setImmutableType(IntersectionType immutableType) { this.immutableType = immutableType; } + @Override public Type getEffectiveType() { return this.effectiveType; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BIteratorType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BIteratorType.java index 46be5354f1a4..13d870f510b6 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BIteratorType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BIteratorType.java @@ -33,6 +33,7 @@ public BIteratorType(String typeName, Module pkg) { super(typeName, pkg, IteratorValue.class); } + @Override public V getZeroValue() { return null; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BJsonType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BJsonType.java index a102f9d4dabc..382a5d4b66f8 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BJsonType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BJsonType.java @@ -88,6 +88,7 @@ public int getTag() { return TypeTags.JSON_TAG; } + @Override public boolean isNilable() { return true; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BMapType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BMapType.java index 2ad5a6b78db0..c69aaa56c144 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BMapType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BMapType.java @@ -78,6 +78,7 @@ public BMapType(String typeName, Type constraint, Module pkg, boolean readonly) * * @return constraint type. */ + @Override public Type getConstrainedType() { return constraint; } @@ -123,12 +124,10 @@ public String toString() { @Override public boolean equals(Object obj) { - if (!super.equals(obj) || !(obj instanceof BMapType)) { + if (!super.equals(obj) || !(obj instanceof BMapType other)) { return false; } - BMapType other = (BMapType) obj; - if (this.readonly != other.readonly) { return false; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BMethodType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BMethodType.java index 360829a47f11..46d25842338c 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BMethodType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BMethodType.java @@ -71,6 +71,7 @@ public ObjectType getParentObjectType() { return parentObjectType; } + @Override public FunctionType getType() { return type; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BNullType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BNullType.java index 45e19ebea9c8..702133228119 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BNullType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BNullType.java @@ -38,6 +38,7 @@ public BNullType(String typeName, Module pkg) { super(typeName, pkg, null); } + @Override public V getZeroValue() { return null; } @@ -52,6 +53,7 @@ public int getTag() { return TypeTags.NULL_TAG; } + @Override public boolean isNilable() { return true; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BObjectType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BObjectType.java index c3ee14297571..a4e609158587 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BObjectType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BObjectType.java @@ -145,6 +145,7 @@ public boolean isIsolated(String methodName) { throw ErrorCreator.createError(StringUtils.fromString("No such method: " + methodName)); } + @Override public void setMethods(MethodType[] methodTypes) { this.methodTypes = methodTypes; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BParameterizedType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BParameterizedType.java index f39bc96f1f70..ca8a47508c11 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BParameterizedType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BParameterizedType.java @@ -29,8 +29,8 @@ */ public class BParameterizedType extends BType implements ParameterizedType { - private Type paramValueType; - private int paramIndex; + private final Type paramValueType; + private final int paramIndex; public BParameterizedType(Type paramValueType, int paramIndex) { super(null, null, null); @@ -40,7 +40,7 @@ public BParameterizedType(Type paramValueType, int paramIndex) { @Override public V getZeroValue() { - return (V) paramValueType.getZeroValue(); + return paramValueType.getZeroValue(); } @Override @@ -58,12 +58,10 @@ public boolean equals(Object obj) { if (this == obj) { return true; } - if (!(obj instanceof BParameterizedType)) { + if (!(obj instanceof BParameterizedType otherParameterizedType)) { return false; } - BParameterizedType otherParameterizedType = (BParameterizedType) obj; - return paramIndex == otherParameterizedType.paramIndex && paramValueType.equals(otherParameterizedType.getParamValueType()); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BReadonlyType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BReadonlyType.java index 856da35eaa16..8fb84c638a1e 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BReadonlyType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BReadonlyType.java @@ -48,6 +48,7 @@ public int getTag() { return TypeTags.READONLY_TAG; } + @Override public boolean isNilable() { return true; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BRecordType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BRecordType.java index aa357855dae5..27b9286de00e 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BRecordType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BRecordType.java @@ -198,14 +198,17 @@ public void setIntersectionType(IntersectionType intersectionType) { this.intersectionType = intersectionType; } + @Override public boolean isSealed() { return sealed; } + @Override public Type getRestFieldType() { return restFieldType; } + @Override public int getTypeFlags() { return typeFlags; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BResourceMethodType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BResourceMethodType.java index 5c6a68d7c5ad..b2f1fe3e37f2 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BResourceMethodType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BResourceMethodType.java @@ -19,6 +19,7 @@ import io.ballerina.runtime.api.Module; import io.ballerina.runtime.api.types.MethodType; +import io.ballerina.runtime.api.types.Parameter; import io.ballerina.runtime.api.types.ResourceMethodType; import io.ballerina.runtime.api.types.Type; @@ -53,9 +54,9 @@ public String toString() { } StringJoiner sj = new StringJoiner(",", "resource function " + accessor + " " + rp.toString() + "(", ") returns (" + type.retType + ")"); - for (int i = 0; i < parameters.length; i++) { - Type type = parameters[i].type; - sj.add(type.getName() + " " + parameters[i].name); + for (Parameter parameter : parameters) { + Type type = parameter.type; + sj.add(type.getName() + " " + parameter.name); } return sj.toString(); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BStreamType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BStreamType.java index f75dc8b6145e..049ba7f16452 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BStreamType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BStreamType.java @@ -35,8 +35,8 @@ */ public class BStreamType extends BType implements StreamType { - private Type constraint; - private Type completionType; + private final Type constraint; + private final Type completionType; /** * Creates a {@link BStreamType} which represents the stream type. @@ -86,10 +86,12 @@ public BStreamType(Type constraint) { this(TypeConstants.STREAM_TNAME, constraint, null); } + @Override public Type getConstrainedType() { return constraint; } + @Override public Type getCompletionType() { return completionType; } @@ -118,11 +120,10 @@ public String toString() { @Override public boolean equals(Object obj) { - if (!super.equals(obj) || !(obj instanceof BStreamType)) { + if (!super.equals(obj) || !(obj instanceof BStreamType other)) { return false; } - BStreamType other = (BStreamType) obj; if (constraint == other.constraint && completionType == other.completionType) { return true; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BStringType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BStringType.java index 359beacd3d21..34be4d3d188f 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BStringType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BStringType.java @@ -47,6 +47,7 @@ public BStringType(String typeName, Module pkg, int tag) { this.tag = tag; } + @Override public V getZeroValue() { return (V) RuntimeConstants.STRING_EMPTY_VALUE; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BStructureType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BStructureType.java index 58b453e9f082..64cf037ebde1 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BStructureType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BStructureType.java @@ -64,14 +64,17 @@ public BStructureType(String typeName, Module pkg, long flags, Class getFields() { return fields; } + @Override public void setFields(Map fields) { this.fields = fields; } + @Override public long getFlags() { return flags; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTableType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTableType.java index 6393166c5f63..1aae344cfd3e 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTableType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTableType.java @@ -59,6 +59,7 @@ public BTableType(Type constraint, boolean readonly) { this.readonly = readonly; } + @Override public Type getConstrainedType() { return constraint; } @@ -67,6 +68,7 @@ public Type getKeyType() { return keyType; } + @Override public String[] getFieldNames() { return fieldNames; } @@ -96,7 +98,7 @@ public String toString() { String stringRep; if (fieldNames.length > 0) { for (String fieldName : fieldNames) { - if (!keyStringBuilder.toString().equals("")) { + if (!keyStringBuilder.toString().isEmpty()) { keyStringBuilder.append(", "); } keyStringBuilder.append(fieldName); @@ -112,11 +114,10 @@ public String toString() { @Override public boolean equals(Object obj) { - if (!super.equals(obj) || !(obj instanceof BTableType)) { + if (!super.equals(obj) || !(obj instanceof BTableType other)) { return false; } - BTableType other = (BTableType) obj; if (constraint == other.constraint && keyType == other.keyType) { return true; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTupleType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTupleType.java index 4e69b2e41dab..21fb42a59f92 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTupleType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTupleType.java @@ -139,10 +139,12 @@ private List getReadOnlyTypes(List typeList) { return readOnlyTypes; } + @Override public List getTupleTypes() { return tupleTypes; } + @Override public Type getRestType() { return restType; } @@ -227,10 +229,9 @@ public boolean equals(Object o) { if (this == o) { return true; } - if (!(o instanceof BTupleType)) { + if (!(o instanceof BTupleType that)) { return false; } - BTupleType that = (BTupleType) o; if (this.isCyclic || that.isCyclic) { if (this.isCyclic != that.isCyclic) { @@ -261,6 +262,7 @@ public boolean isPureType() { return TypeFlags.isFlagOn(this.typeFlags, TypeFlags.PURETYPE); } + @Override public int getTypeFlags() { return this.typeFlags; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BType.java index 866432570c59..5d2aba9ddc8f 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BType.java @@ -66,6 +66,7 @@ public Class getValueClass() { * @param Type of the value * @return Default value of the type */ + @Override public abstract V getZeroValue(); /** @@ -76,8 +77,10 @@ public Class getValueClass() { * @param Type of the value * @return Init value of this type */ + @Override public abstract V getEmptyValue(); + @Override public abstract int getTag(); public String toString() { @@ -90,8 +93,7 @@ public boolean equals(Object obj) { return true; } - if (obj instanceof BType) { - BType other = (BType) obj; + if (obj instanceof BType other) { if (!this.typeName.equals(other.getName())) { return false; @@ -126,6 +128,7 @@ public boolean equals(Object obj) { return false; } + @Override public boolean isNilable() { return false; } @@ -134,10 +137,12 @@ public int hashCode() { return hashCode; } + @Override public String getName() { return typeName == null ? "" : typeName; } + @Override public final String getQualifiedName() { String name = getName(); if (name.isEmpty()) { @@ -147,30 +152,37 @@ public final String getQualifiedName() { return pkg == null ? name : pkg.toString() + ":" + name; } + @Override public Module getPackage() { return pkg; } + @Override public boolean isPublic() { return false; } + @Override public boolean isNative() { return false; } + @Override public boolean isAnydata() { return this.getTag() <= TypeTags.ANYDATA_TAG; } + @Override public boolean isPureType() { return this.getTag() == TypeTags.ERROR_TAG || this.isAnydata(); } + @Override public boolean isReadOnly() { return false; } + @Override public Type getImmutableType() { if (TypeChecker.isInherentlyImmutableType(this)) { return this; @@ -180,6 +192,7 @@ public Type getImmutableType() { throw ErrorCreator.createError(StringUtils.fromString(this.typeName + " cannot be immutable")); } + @Override public void setImmutableType(IntersectionType immutableType) { // Do nothing since already set. // For types that immutable type may be set later, the relevant type overrides this method. @@ -189,26 +202,32 @@ private boolean hasAllNullConstituents(Module module) { return module.getOrg() == null && module.getName() == null && module.getMajorVersion() == null; } + @Override public Module getPkg() { return pkg; } + @Override public long getFlags() { return 0; } + @Override public void setCachedReferredType(Type type) { this.cachedReferredType = type; } + @Override public Type getCachedReferredType() { return this.cachedReferredType; } + @Override public void setCachedImpliedType(Type type) { this.cachedImpliedType = type; } + @Override public Type getCachedImpliedType() { return this.cachedImpliedType; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTypeIdSet.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTypeIdSet.java index f80780d87586..f08e2d340f8f 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTypeIdSet.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTypeIdSet.java @@ -96,8 +96,7 @@ public boolean equals(Object obj) { return true; } - if (obj instanceof BTypeId) { - BTypeId that = (BTypeId) obj; + if (obj instanceof BTypeId that) { return this.name.equals(that.name) && this.pkg.equals(that.pkg); } return false; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTypeReferenceType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTypeReferenceType.java index f43cd540dc0e..4d228b2d78f6 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTypeReferenceType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTypeReferenceType.java @@ -66,8 +66,8 @@ public boolean equals(Object obj) { return true; } - if (obj instanceof BTypeReferenceType) { - return this.referredType.equals(((BTypeReferenceType) obj).getReferredType()); + if (obj instanceof BTypeReferenceType typeReferenceType) { + return this.referredType.equals(typeReferenceType.getReferredType()); } return false; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTypedescType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTypedescType.java index a03a30737ad7..a6988bc263cb 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTypedescType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BTypedescType.java @@ -64,12 +64,13 @@ public boolean equals(Object obj) { if (this == obj) { return true; } - if (obj instanceof BTypedescType) { - return constraint.equals(((BTypedescType) obj).getConstraint()); + if (obj instanceof BTypedescType typedescType) { + return constraint.equals(typedescType.getConstraint()); } return false; } + @Override public Type getConstraint() { return constraint; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BUnionType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BUnionType.java index 527ce7d0f651..3f957eac231a 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BUnionType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BUnionType.java @@ -201,6 +201,7 @@ public void setCyclic(boolean isCyclic) { this.isCyclic = isCyclic; } + @Override public boolean isNilable() { if (memberTypes == null || memberTypes.isEmpty()) { return true; @@ -268,6 +269,7 @@ private void setFlagsBasedOnMembers() { this.readonly = readonly; } + @Override public List getMemberTypes() { return memberTypes; } @@ -361,12 +363,10 @@ public boolean equals(Object o) { return true; } - if (!(o instanceof BUnionType)) { + if (!(o instanceof BUnionType that)) { return false; } - BUnionType that = (BUnionType) o; - if (this.isCyclic || that.isCyclic) { if (this.isCyclic != that.isCyclic) { return false; @@ -404,6 +404,7 @@ public int getTypeFlags() { return this.typeFlags; } + @Override public long getFlags() { return this.flags; } @@ -439,28 +440,24 @@ public void mergeUnionType(BUnionType unionType) { } this.isCyclic = true; for (Type member : unionType.getMemberTypes()) { - if (member instanceof BArrayType) { - BArrayType arrayType = (BArrayType) member; + if (member instanceof BArrayType arrayType) { if (TypeUtils.getImpliedType(arrayType.getElementType()) == unionType) { BArrayType newArrayType = new BArrayType(this, this.readonly); this.addMember(newArrayType); continue; } - } else if (member instanceof BMapType) { - BMapType mapType = (BMapType) member; + } else if (member instanceof BMapType mapType) { if (mapType.getConstrainedType() == unionType) { BMapType newMapType = new BMapType(this, this.readonly); this.addMember(newMapType); continue; } - } else if (member instanceof BTableType) { - BTableType tableType = (BTableType) member; + } else if (member instanceof BTableType tableType) { if (tableType.getConstrainedType() == unionType) { BTableType newTableType = new BTableType(this, tableType.isReadOnly()); this.addMember(newTableType); continue; - } else if (tableType.getConstrainedType() instanceof BMapType) { - BMapType mapType = (BMapType) tableType.getConstrainedType(); + } else if (tableType.getConstrainedType() instanceof BMapType mapType) { if (mapType.getConstrainedType() == unionType) { BMapType newMapType = new BMapType(this); BTableType newTableType = new BTableType(newMapType, diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BXmlAttributesType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BXmlAttributesType.java index 0d08050ef73f..d9edf897051a 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BXmlAttributesType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BXmlAttributesType.java @@ -38,6 +38,7 @@ public BXmlAttributesType(String typeName, Module pkg) { super(typeName, pkg, null); } + @Override public V getZeroValue() { return null; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BXmlType.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BXmlType.java index 187c15dfb6c2..c48c9d085594 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BXmlType.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/types/BXmlType.java @@ -99,11 +99,10 @@ public boolean isAnydata() { @Override public boolean equals(Object obj) { - if (!(this == obj && obj instanceof BXmlType)) { + if (!(this == obj && obj instanceof BXmlType other)) { return false; } - BXmlType other = (BXmlType) obj; if (constraint == other.constraint) { return true; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/util/CompatibilityChecker.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/util/CompatibilityChecker.java index 52f075851702..e5ed38a11e16 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/util/CompatibilityChecker.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/util/CompatibilityChecker.java @@ -26,12 +26,15 @@ * @since 1.0.1 */ -public class CompatibilityChecker { +public final class CompatibilityChecker { private static final String JAVA_VERSION = "java.version"; private static final String VERSION_ZERO = "0"; private static final PrintStream stderr = System.err; + private CompatibilityChecker() { + } + /** * Check for the compatibility of a given java version against the current java runtime version. * This assumes the versions are in the following formats: diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/util/LargeStructureUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/util/LargeStructureUtils.java index 20a86e2b2841..252b866237a0 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/util/LargeStructureUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/util/LargeStructureUtils.java @@ -30,7 +30,7 @@ * * @since 2201.8.0 */ -public class LargeStructureUtils { +public final class LargeStructureUtils { private LargeStructureUtils() {} @@ -59,7 +59,7 @@ public static void setKeyValueEntry(HandleValue arrayList, Object key, Object va public static void setSpreadFieldEntry(HandleValue arrayList, Object spreadFieldEntry, long index) { BMapInitialValueEntry[] arr = (BMapInitialValueEntry[]) arrayList.getValue(); - arr[(int) index] = new MappingInitialValueEntry.SpreadFieldEntry((BMap) spreadFieldEntry); + arr[(int) index] = new MappingInitialValueEntry.SpreadFieldEntry((BMap) spreadFieldEntry); } } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/util/RuntimeUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/util/RuntimeUtils.java index 11d4dc9d767f..a89fae22b26b 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/util/RuntimeUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/util/RuntimeUtils.java @@ -54,7 +54,7 @@ * @since 0.995.0 */ -public class RuntimeUtils { +public final class RuntimeUtils { private static final String CRASH_LOGGER = "b7a.log.crash"; private static final PrintStream errStream = System.err; @@ -130,8 +130,8 @@ public ParamInfo(boolean hasDefaultable, String name, Type type) { } public static void handleBErrorAndExit(Throwable throwable) { - if (throwable instanceof ErrorValue) { - printToConsole((ErrorValue) throwable); + if (throwable instanceof ErrorValue errorValue) { + printToConsole(errorValue); } Runtime.getRuntime().exit(1); } @@ -142,8 +142,8 @@ public static void handleAllRuntimeErrorsAndExit(Throwable throwable) { } public static void handleAllRuntimeErrors(Throwable throwable) { - if (throwable instanceof ErrorValue) { - printToConsole((ErrorValue) throwable); + if (throwable instanceof ErrorValue errorValue) { + printToConsole(errorValue); } else { logBadSad(throwable); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/util/StringUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/util/StringUtils.java index 6cb05a948a15..fa44bae7cf50 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/util/StringUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/util/StringUtils.java @@ -47,7 +47,7 @@ * * @since 2201.6.0 */ -public class StringUtils { +public final class StringUtils { public static final String STR_CYCLE = "..."; public static final String TO_STRING = "toString"; @@ -77,7 +77,7 @@ public static String getStringVal(Object value, BLink parent) { return STR_CYCLE; } if (type.getTag() == TypeTags.MAP_TAG || type.getTag() == TypeTags.RECORD_TYPE_TAG) { - MapValueImpl mapValue = (MapValueImpl) value; + MapValueImpl mapValue = (MapValueImpl) value; return mapValue.stringValue(parent); } if (type.getTag() == TypeTags.ARRAY_TAG || type.getTag() == TypeTags.TUPLE_TAG) { @@ -136,7 +136,7 @@ public static String getExpressionStringVal(Object value, BLink parent) { return STR_CYCLE + "[" + node.getIndex() + "]"; } if (type.getTag() == TypeTags.MAP_TAG || type.getTag() == TypeTags.RECORD_TYPE_TAG) { - MapValueImpl mapValue = (MapValueImpl) value; + MapValueImpl mapValue = (MapValueImpl) value; return mapValue.expressionStringValue(parent); } if (type.getTag() == TypeTags.ARRAY_TAG || type.getTag() == TypeTags.TUPLE_TAG) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/AbstractArrayValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/AbstractArrayValue.java index 841c6a0b3248..ab80640c69d0 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/AbstractArrayValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/AbstractArrayValue.java @@ -118,6 +118,7 @@ public Object shift() { * @param values values to add to the start of the array */ + @Override public void unshift(Object[] values) { unshift(0, values); } @@ -127,6 +128,7 @@ public int size() { return size; } + @Override public boolean isEmpty() { return size == 0; } @@ -162,7 +164,7 @@ public String getJSONString() { * {@inheritDoc} */ @Override - public IteratorValue getIterator() { + public IteratorValue getIterator() { return new ArrayIterator(this); } @@ -205,6 +207,7 @@ protected void initializeIteratorNextReturnType() { iteratorNextReturnType = IteratorUtils.createIteratorNextReturnType(type); } + @Override public Type getIteratorNextReturnType() { if (iteratorNextReturnType == null) { initializeIteratorNextReturnType(); @@ -276,7 +279,7 @@ protected void prepareForAddForcefully(int intIndex, int currentArraySize) { * * @since 0.995.0 */ - static class ArrayIterator implements IteratorValue { + static class ArrayIterator implements IteratorValue { ArrayValue array; long cursor = 0; long length; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/AbstractObjectValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/AbstractObjectValue.java index 068b97bb03a4..07d20399f30d 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/AbstractObjectValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/AbstractObjectValue.java @@ -132,9 +132,10 @@ public boolean getBooleanValue(BString fieldName) { return (boolean) get(fieldName); } + @SuppressWarnings("rawtypes") @Override public BMap getMapValue(BString fieldName) { - return (MapValueImpl) get(fieldName); + return (MapValueImpl) get(fieldName); } @Override diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ArrayValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ArrayValue.java index b09c4b297e3f..af4febe73476 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ArrayValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ArrayValue.java @@ -30,7 +30,13 @@ public interface ArrayValue extends RefValue, BArray, CollectionValue { String getJSONString(); + @Override Object shift(long index); + Object pop(long index); + + Object remove(long index); + + @Override void setLength(long length); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ArrayValueImpl.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ArrayValueImpl.java index 4bf61d2a613b..e983854997ef 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ArrayValueImpl.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ArrayValueImpl.java @@ -185,57 +185,63 @@ public BTypedesc getTypedesc() { @Override public Object reverse() { - switch (elementType.getTag()) { - case TypeTags.INT_TAG: - case TypeTags.SIGNED32_INT_TAG: - case TypeTags.SIGNED16_INT_TAG: - case TypeTags.SIGNED8_INT_TAG: - case TypeTags.UNSIGNED32_INT_TAG: - case TypeTags.UNSIGNED16_INT_TAG: - case TypeTags.UNSIGNED8_INT_TAG: + return switch (elementType.getTag()) { + case TypeTags.INT_TAG, + TypeTags.SIGNED32_INT_TAG, + TypeTags.SIGNED16_INT_TAG, + TypeTags.SIGNED8_INT_TAG, + TypeTags.UNSIGNED32_INT_TAG, + TypeTags.UNSIGNED16_INT_TAG, + TypeTags.UNSIGNED8_INT_TAG -> { for (int i = size - 1, j = 0; j < size / 2; i--, j++) { long temp = intValues[j]; intValues[j] = intValues[i]; intValues[i] = temp; } - return intValues; - case TypeTags.STRING_TAG: - case TypeTags.CHAR_STRING_TAG: + yield intValues; + } + case TypeTags.STRING_TAG, + TypeTags.CHAR_STRING_TAG -> { for (int i = size - 1, j = 0; j < size / 2; i--, j++) { BString temp = bStringValues[j]; bStringValues[j] = bStringValues[i]; bStringValues[i] = temp; } - return bStringValues; - case TypeTags.FLOAT_TAG: + yield bStringValues; + } + case TypeTags.FLOAT_TAG -> { for (int i = size - 1, j = 0; j < size / 2; i--, j++) { double temp = floatValues[j]; floatValues[j] = floatValues[i]; floatValues[i] = temp; } - return floatValues; - case TypeTags.BOOLEAN_TAG: + yield floatValues; + } + case TypeTags.BOOLEAN_TAG -> { for (int i = size - 1, j = 0; j < size / 2; i--, j++) { boolean temp = booleanValues[j]; booleanValues[j] = booleanValues[i]; booleanValues[i] = temp; } - return booleanValues; - case TypeTags.BYTE_TAG: + yield booleanValues; + } + case TypeTags.BYTE_TAG -> { for (int i = size - 1, j = 0; j < size / 2; i--, j++) { byte temp = byteValues[j]; byteValues[j] = byteValues[i]; byteValues[i] = temp; } - return byteValues; - default: + yield byteValues; + } + default -> { for (int i = size - 1, j = 0; j < size / 2; i--, j++) { Object temp = refValues[j]; refValues[j] = refValues[i]; refValues[i] = temp; } - return refValues; - } + yield refValues; + } + }; } public ArrayValueImpl(ArrayType type, long size) { @@ -306,27 +312,21 @@ public ArrayValueImpl(Type type, long size, BListInitialValueEntry[] initialValu @Override public Object get(long index) { rangeCheckForGet(index, size); - switch (this.elementReferredType.getTag()) { - case TypeTags.INT_TAG: - case TypeTags.SIGNED32_INT_TAG: - case TypeTags.SIGNED16_INT_TAG: - case TypeTags.SIGNED8_INT_TAG: - case TypeTags.UNSIGNED32_INT_TAG: - case TypeTags.UNSIGNED16_INT_TAG: - case TypeTags.UNSIGNED8_INT_TAG: - return intValues[(int) index]; - case TypeTags.BOOLEAN_TAG: - return booleanValues[(int) index]; - case TypeTags.BYTE_TAG: - return Byte.toUnsignedInt(byteValues[(int) index]); - case TypeTags.FLOAT_TAG: - return floatValues[(int) index]; - case TypeTags.STRING_TAG: - case TypeTags.CHAR_STRING_TAG: - return bStringValues[(int) index]; - default: - return refValues[(int) index]; - } + return switch (this.elementReferredType.getTag()) { + case TypeTags.INT_TAG, + TypeTags.SIGNED32_INT_TAG, + TypeTags.SIGNED16_INT_TAG, + TypeTags.SIGNED8_INT_TAG, + TypeTags.UNSIGNED32_INT_TAG, + TypeTags.UNSIGNED16_INT_TAG, + TypeTags.UNSIGNED8_INT_TAG -> intValues[(int) index]; + case TypeTags.BOOLEAN_TAG -> booleanValues[(int) index]; + case TypeTags.BYTE_TAG -> Byte.toUnsignedInt(byteValues[(int) index]); + case TypeTags.FLOAT_TAG -> floatValues[(int) index]; + case TypeTags.STRING_TAG, + TypeTags.CHAR_STRING_TAG -> bStringValues[(int) index]; + default -> refValues[(int) index]; + }; } public Object getRefValue(int index) { @@ -705,6 +705,16 @@ public void append(Object value) { add(this.size, value); } + @Override + public Object pop(long index) { + return shift(index); + } + + @Override + public Object remove(long index) { + return shift(index); + } + @Override public Object shift(long index) { handleImmutableArrayValue(); @@ -896,8 +906,8 @@ public Object copy(Map refs) { valueArray = new ArrayValueImpl(values, arrayType); IntStream.range(0, this.size).forEach(i -> { Object value = this.refValues[i]; - if (value instanceof BRefValue) { - values[i] = ((BRefValue) value).copy(refs); + if (value instanceof BRefValue refValue) { + values[i] = refValue.copy(refs); } else { values[i] = value; } @@ -925,6 +935,7 @@ public Object frozenCopy(Map refs) { * @param endIndex index of first member not to include in the slice * @return array slice within specified range */ + @Override public ArrayValueImpl slice(long startIndex, long endIndex) { ArrayValueImpl slicedArray; int slicedSize = (int) (endIndex - startIndex); @@ -1065,8 +1076,8 @@ public void freezeDirect() { if (this.elementType == null || this.elementReferredType.getTag() > TypeTags.BOOLEAN_TAG) { for (int i = 0; i < this.size; i++) { Object value = this.getRefValue(i); - if (value instanceof BRefValue) { - ((BRefValue) value).freezeDirect(); + if (value instanceof BRefValue refValue) { + refValue.freezeDirect(); } } } @@ -1077,7 +1088,7 @@ public void freezeDirect() { * {@inheritDoc} */ @Override - public IteratorValue getIterator() { + public IteratorValue getIterator() { return new ArrayIterator(this); } @@ -1328,51 +1339,39 @@ private void unshiftArray(long index, int unshiftByN, int arrLength) { } private Object getArrayFromType(int typeTag) { - switch (typeTag) { - case TypeTags.INT_TAG: - case TypeTags.SIGNED32_INT_TAG: - case TypeTags.SIGNED16_INT_TAG: - case TypeTags.SIGNED8_INT_TAG: - case TypeTags.UNSIGNED32_INT_TAG: - case TypeTags.UNSIGNED16_INT_TAG: - case TypeTags.UNSIGNED8_INT_TAG: - return intValues; - case TypeTags.BOOLEAN_TAG: - return booleanValues; - case TypeTags.BYTE_TAG: - return byteValues; - case TypeTags.FLOAT_TAG: - return floatValues; - case TypeTags.STRING_TAG: - case TypeTags.CHAR_STRING_TAG: - return bStringValues; - default: - return refValues; - } + return switch (typeTag) { + case TypeTags.INT_TAG, + TypeTags.SIGNED32_INT_TAG, + TypeTags.SIGNED16_INT_TAG, + TypeTags.SIGNED8_INT_TAG, + TypeTags.UNSIGNED32_INT_TAG, + TypeTags.UNSIGNED16_INT_TAG, + TypeTags.UNSIGNED8_INT_TAG -> intValues; + case TypeTags.BOOLEAN_TAG -> booleanValues; + case TypeTags.BYTE_TAG -> byteValues; + case TypeTags.FLOAT_TAG -> floatValues; + case TypeTags.STRING_TAG, + TypeTags.CHAR_STRING_TAG -> bStringValues; + default -> refValues; + }; } private int getCurrentArrayLength() { - switch (elementType.getTag()) { - case TypeTags.INT_TAG: - case TypeTags.SIGNED32_INT_TAG: - case TypeTags.SIGNED16_INT_TAG: - case TypeTags.SIGNED8_INT_TAG: - case TypeTags.UNSIGNED32_INT_TAG: - case TypeTags.UNSIGNED16_INT_TAG: - case TypeTags.UNSIGNED8_INT_TAG: - return intValues.length; - case TypeTags.BOOLEAN_TAG: - return booleanValues.length; - case TypeTags.BYTE_TAG: - return byteValues.length; - case TypeTags.FLOAT_TAG: - return floatValues.length; - case TypeTags.STRING_TAG: - case TypeTags.CHAR_STRING_TAG: - return bStringValues.length; - default: - return refValues.length; - } + return switch (elementType.getTag()) { + case TypeTags.INT_TAG, + TypeTags.SIGNED32_INT_TAG, + TypeTags.SIGNED16_INT_TAG, + TypeTags.SIGNED8_INT_TAG, + TypeTags.UNSIGNED32_INT_TAG, + TypeTags.UNSIGNED16_INT_TAG, + TypeTags.UNSIGNED8_INT_TAG -> intValues.length; + case TypeTags.BOOLEAN_TAG -> booleanValues.length; + case TypeTags.BYTE_TAG -> byteValues.length; + case TypeTags.FLOAT_TAG -> floatValues.length; + case TypeTags.STRING_TAG, + TypeTags.CHAR_STRING_TAG -> bStringValues.length; + default -> refValues.length; + }; } @Override diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/BmpStringValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/BmpStringValue.java index 7654836e633a..38f3b6603f78 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/BmpStringValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/BmpStringValue.java @@ -1,75 +1,75 @@ - /* - * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. 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. - */ +/* + * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.runtime.internal.values; import io.ballerina.runtime.api.values.BString; - /** - * Represent ballerina strings containing only unicode basic multilingual plane characters. - * - * @since 1.0.5 - */ - public class BmpStringValue extends StringValue { +/** + * Represent ballerina strings containing only unicode basic multilingual plane characters. + * + * @since 1.0.5 + */ +public class BmpStringValue extends StringValue { - public BmpStringValue(String value) { - super(value, false); - } + public BmpStringValue(String value) { + super(value, false); + } - @Override - public int getCodePoint(int index) { - return value.charAt(index); - } + @Override + public int getCodePoint(int index) { + return value.charAt(index); + } - @Override - public int length() { - return value.length(); - } + @Override + public int length() { + return value.length(); + } - @Override - public BString concat(BString str) { - StringValue stringValue = (StringValue) str; - if (stringValue.isNonBmp) { - int[] otherSurrogates = ((NonBmpStringValue) str).getSurrogates(); - int[] newSurrogates = new int[otherSurrogates.length]; - int length = length(); - for (int i = 0; i < otherSurrogates.length; i++) { - newSurrogates[i] = otherSurrogates[i] + length; - } - return new NonBmpStringValue(this.value + str.getValue(), newSurrogates); - } - return new BmpStringValue(this.value + str.getValue()); - } + @Override + public BString concat(BString str) { + StringValue stringValue = (StringValue) str; + if (stringValue.isNonBmp) { + int[] otherSurrogates = ((NonBmpStringValue) str).getSurrogates(); + int[] newSurrogates = new int[otherSurrogates.length]; + int length = length(); + for (int i = 0; i < otherSurrogates.length; i++) { + newSurrogates[i] = otherSurrogates[i] + length; + } + return new NonBmpStringValue(this.value + str.getValue(), newSurrogates); + } + return new BmpStringValue(this.value + str.getValue()); + } - @Override - public Long indexOf(BString str, int fromIndex) { - long index = value.indexOf(str.getValue(), fromIndex); - return index >= 0 ? index : null; - } + @Override + public Long indexOf(BString str, int fromIndex) { + long index = value.indexOf(str.getValue(), fromIndex); + return index >= 0 ? index : null; + } - @Override - public Long lastIndexOf(BString str, int fromIndex) { - long index = value.lastIndexOf(str.getValue(), fromIndex); - return index >= 0 ? index : null; - } + @Override + public Long lastIndexOf(BString str, int fromIndex) { + long index = value.lastIndexOf(str.getValue(), fromIndex); + return index >= 0 ? index : null; + } - @Override - public BString substring(int beginIndex, int endIndex) { - return new BmpStringValue(value.substring(beginIndex, endIndex)); - } - } + @Override + public BString substring(int beginIndex, int endIndex) { + return new BmpStringValue(value.substring(beginIndex, endIndex)); + } +} diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ChannelDetails.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ChannelDetails.java index 9f01d027a179..1bbbba69adbc 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ChannelDetails.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ChannelDetails.java @@ -1,51 +1,51 @@ - /* - * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. 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.runtime.internal.values; +/* + * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.runtime.internal.values; - /** - * Represents a channel info. - * - * @since 0.995.0 - */ - public class ChannelDetails { +/** + * Represents a channel info. + * + * @since 0.995.0 + */ +public class ChannelDetails { - public String name; - public boolean channelInSameStrand; - public boolean send; + public String name; + public boolean channelInSameStrand; + public boolean send; - public ChannelDetails(String name, boolean channelInSameStrand, boolean send) { - this.name = name; - this.channelInSameStrand = channelInSameStrand; - this.send = send; - } + public ChannelDetails(String name, boolean channelInSameStrand, boolean send) { + this.name = name; + this.channelInSameStrand = channelInSameStrand; + this.send = send; + } - @Override - public String toString() { - return name; - } + @Override + public String toString() { + return name; + } - @Override - public int hashCode() { - return name.hashCode(); - } + @Override + public int hashCode() { + return name.hashCode(); + } - @Override - public boolean equals(Object o) { - return (o instanceof ChannelDetails) && (((ChannelDetails) o).name.equals(this.name)); - } - } + @Override + public boolean equals(Object o) { + return (o instanceof ChannelDetails channelDetails) && (channelDetails.name.equals(this.name)); + } +} diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/CharIterator.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/CharIterator.java index 9e5c4cea6bf1..e1201b121294 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/CharIterator.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/CharIterator.java @@ -23,7 +23,7 @@ * * @since 2.0 */ -public class CharIterator implements IteratorValue { +public class CharIterator implements IteratorValue { StringValue value; long cursor = 0; @@ -37,7 +37,7 @@ public class CharIterator implements IteratorValue { } @Override - public Object next() { + public String next() { long currentIndex = this.cursor++; if (value.isNonBmp) { return getNonBmpCharWithSurrogates(currentIndex); diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/CollectionValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/CollectionValue.java index 0aad3287ad33..e321a62e9141 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/CollectionValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/CollectionValue.java @@ -31,5 +31,6 @@ */ public interface CollectionValue extends BCollection { - IteratorValue getIterator(); + @Override + IteratorValue getIterator(); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/DecimalValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/DecimalValue.java index aafa40069354..2771264baf37 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/DecimalValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/DecimalValue.java @@ -110,6 +110,7 @@ private static BigDecimal getValidDecimalValue(BigDecimal bd) { * Get value of the decimal. * @return the value */ + @Override public BigDecimal decimalValue() { return this.value; } @@ -119,6 +120,7 @@ public BigDecimal decimalValue() { * May result in a {@code ErrorValue} * @return the integer value */ + @Override public long intValue() { if (!isDecimalWithinIntRange(this)) { @@ -144,6 +146,7 @@ public static boolean isDecimalWithinIntRange(DecimalValue decimalValue) { * May result in a {@code ErrorValue} * @return the byte value */ + @Override public int byteValue() { int intVal = (int) Math.rint(this.value.doubleValue()); @@ -162,6 +165,7 @@ private static boolean isByteLiteral(long longValue) { * Get the float value. * @return the double value */ + @Override public double floatValue() { return value.doubleValue(); } @@ -170,6 +174,7 @@ public double floatValue() { * Check the given value represents true or false. * @return true if the value is non zero */ + @Override public boolean booleanValue() { return value.compareTo(BigDecimal.ZERO) != 0; } @@ -189,6 +194,7 @@ public Object frozenCopy(Map refs) { * @return string value * @param parent The link to the parent node */ + @Override public String stringValue(BLink parent) { if (this.valueKind != DecimalValueKind.OTHER) { return this.valueKind.getValue(); @@ -201,6 +207,7 @@ public String stringValue(BLink parent) { * @return string value in expression style * @param parent The link to the parent node */ + @Override public String expressionStringValue(BLink parent) { if (this.valueKind != DecimalValueKind.OTHER) { return this.valueKind.getValue() + "d"; @@ -212,6 +219,7 @@ public String expressionStringValue(BLink parent) { * Get the {@code BigDecimal} value. * @return the decimal value */ + @Override public BigDecimal value() { return this.value; } @@ -220,6 +228,7 @@ public BigDecimal value() { * Get the {@code BType} of the value. * @return the type */ + @Override public Type getType() { return PredefinedTypes.TYPE_DECIMAL; } @@ -262,8 +271,8 @@ public DecimalValue subtract(DecimalValue subtrahend) { } /** - * Returns a decimal whose value is (this × - * multiplicand). + * Returns a decimal whose value is {@code (this × + * multiplicand)}. * @param multiplicand value to be multiplied * @return value after multiplication */ @@ -321,6 +330,7 @@ public DecimalValue remainder(DecimalValue divisor) { * Returns a decimal whose value is {@code (-this)}. * @return {@code -this} */ + @Override public DecimalValue negate() { if (this.valueKind == DecimalValueKind.OTHER) { return new DecimalValue(this.decimalValue().negate()); @@ -357,6 +367,7 @@ public BDecimal remainder(BDecimal divisor) { * Returns value kind of {@code (-this)}. * @return value kind */ + @Override public DecimalValueKind getValueKind() { return valueKind; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ErrorValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ErrorValue.java index 66733b0fe907..dd534b85352e 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ErrorValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ErrorValue.java @@ -66,7 +66,6 @@ */ public class ErrorValue extends BError implements RefValue { - private static final long serialVersionUID = 1L; private static final PrintStream outStream = System.err; private final Type type; @@ -75,8 +74,7 @@ public class ErrorValue extends BError implements RefValue { private final BError cause; private final Object details; - private static final String GENERATE_OBJECT_CLASS_PREFIX = "$value$"; - private static final String SPLIT_CLASS_SUFFIX_REGEX = "\\$split\\$\\d"; + private static final String GENERATED_CLASS_TEXTS_REGEX = "\\$value\\$|\\$split\\$\\d|lambdas.\\$_generated\\d*"; private static final String GENERATE_PKG_INIT = "___init_"; private static final String GENERATE_PKG_START = "___start_"; private static final String GENERATE_PKG_STOP = "___stop_"; @@ -145,8 +143,8 @@ private String getCauseToString(BLink parent) { private String getDetailsToString(BLink parent) { StringJoiner sj = new StringJoiner(","); - for (Object key : ((MapValue) details).getKeys()) { - Object value = ((MapValue) details).get(key); + for (Object key : ((MapValue) details).getKeys()) { + Object value = ((MapValue) details).get(key); if (value == null) { sj.add(key + "=null"); } else { @@ -177,8 +175,8 @@ private String getModuleNameToString() { private String getDetailsToBalString(BLink parent) { StringJoiner sj = new StringJoiner(","); - for (Object key : ((MapValue) details).getKeys()) { - Object value = ((MapValue) details).get(key); + for (Object key : ((MapValue) details).getKeys()) { + Object value = ((MapValue) details).get(key); sj.add(key + "=" + getExpressionStringVal(value, parent)); } return "," + sj; @@ -261,9 +259,10 @@ public BString getErrorMessage() { * * @return detail record */ + @Override public Object getDetails() { - if (details instanceof BRefValue) { - return ((BRefValue) details).frozenCopy(new HashMap<>()); + if (details instanceof BRefValue bRefValue) { + return bRefValue.frozenCopy(new HashMap<>()); } return details; } @@ -304,6 +303,7 @@ public StackTraceElement[] getStackTrace() { * Returns error stack trace as a string. * @return stack trace string */ + @Override public String getPrintableStackTrace() { String errorMsg = getPrintableError(); StringBuilder sb = new StringBuilder(); @@ -401,7 +401,7 @@ private boolean isEmptyDetail() { if (details == null) { return true; } - return (details instanceof MapValue) && ((MapValue) details).isEmpty(); + return (details instanceof MapValue mapValue) && mapValue.isEmpty(); } private Optional filterStackTraceElement(StackTraceElement stackFrame, int currentIndex) { @@ -444,7 +444,7 @@ private Optional filterStackTraceElement(StackTraceElement st } private String cleanupClassName(String className) { - return className.replace(GENERATE_OBJECT_CLASS_PREFIX, "").replaceAll(SPLIT_CLASS_SUFFIX_REGEX, ""); + return className.replaceAll(GENERATED_CLASS_TEXTS_REGEX, ""); } private boolean isCompilerAddedName(String name) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/FPValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/FPValue.java index 44f8b914744a..beedcc984d45 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/FPValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/FPValue.java @@ -60,20 +60,24 @@ public FPValue(Function function, Type type, String strandName, boolean is this.isConcurrent = isConcurrent; } + @Override public R call(T t) { return this.function.apply(t); } + @Override public BFuture asyncCall(Object[] args, StrandMetadata metaData) { return this.asyncCall(args, o -> o, metaData); } + @Override public BFuture asyncCall(Object[] args, Function resultHandleFunction, - StrandMetadata metaData) { - return AsyncUtils.invokeFunctionPointerAsync(this, this.strandName, metaData, + StrandMetadata metaData) { + return AsyncUtils.invokeFunctionPointerAsync((BFunctionPointer) this, this.strandName, metaData, args, resultHandleFunction, Scheduler.getStrand().scheduler); } + @Override public Function getFunction() { return this.function; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/FutureValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/FutureValue.java index 76709936a568..44a9c34da136 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/FutureValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/FutureValue.java @@ -1,164 +1,170 @@ - /* - * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. 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.runtime.internal.values; - - import io.ballerina.runtime.api.async.Callback; - import io.ballerina.runtime.api.types.Type; - import io.ballerina.runtime.api.values.BFuture; - import io.ballerina.runtime.api.values.BLink; - import io.ballerina.runtime.api.values.BTypedesc; - import io.ballerina.runtime.internal.scheduling.Strand; - import io.ballerina.runtime.internal.types.BFutureType; - import io.ballerina.runtime.internal.util.StringUtils; - - import java.util.Map; - import java.util.StringJoiner; - - /** - *

- * Represent a Ballerina future in Java. - *

- *

- * Note: This is an internal API and may change in future versions. - *

- * - * @since 0.995.0 - */ - public class FutureValue implements BFuture, RefValue { - - private BTypedesc typedesc; - - public Strand strand; - - public Object result; - - public boolean isDone; - - public Throwable panic; - - public Callback callback; - - private boolean waited; - - Type type; - - @Deprecated - public FutureValue(Strand strand, Callback callback, Type constraint) { - this.strand = strand; - this.callback = callback; - this.type = new BFutureType(constraint); - } - - @Override - public String stringValue(BLink parent) { - StringJoiner sj = new StringJoiner(",", "{", "}"); - sj.add("isDone:" + isDone); - if (isDone) { - sj.add("result:" + StringUtils.getStringVal(result, parent)); - } - if (panic != null) { - sj.add("panic:" + panic.getLocalizedMessage()); - } - return "future " + sj; - } - - @Override - public String expressionStringValue(BLink parent) { - return stringValue(parent); - } - - @Override - public Type getType() { - return this.type; - } - - @Override - public Object copy(Map refs) { - throw new UnsupportedOperationException(); - } - - @Override - public Object frozenCopy(Map refs) { - throw new UnsupportedOperationException(); - } - - @Override - public BTypedesc getTypedesc() { - if (this.typedesc == null) { - this.typedesc = new TypedescValueImpl(this.type); - } - return typedesc; - } - - public void cancel() { - this.strand.cancel = true; - } - - /** - * Returns the strand that the future is attached to. - * @return {@code Strand} - */ - public Strand getStrand() { - return this.strand; - } - - /** - * Returns the result value of the future. - * @return result value - */ - public Object getResult() { - return this.result; - } - - /** - * Returns completion status of the {@code Strand} that the future is attached. - * @return true if future is completed - */ - public boolean isDone() { - return this.isDone; - } - - /** - * Returns {@code Throwable} if the attached strand panic. - * @return panic error or null if not panic occurred - */ - public Throwable getPanic() { - return this.panic; - } - - /** - * {@code CallableUnitCallback} listening on the completion of this future. - * @return registered {@code CallableUnitCallback} - */ - public Callback getCallback() { - return this.callback; - } - - @Override - public String toString() { - return stringValue(null); - } - - public boolean hasWaited() { - return waited; - } - - public void setWaited(boolean waited) { - this.waited = waited; - } - } +/* + * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.runtime.internal.values; + +import io.ballerina.runtime.api.async.Callback; +import io.ballerina.runtime.api.types.Type; +import io.ballerina.runtime.api.values.BFuture; +import io.ballerina.runtime.api.values.BLink; +import io.ballerina.runtime.api.values.BTypedesc; +import io.ballerina.runtime.internal.scheduling.Strand; +import io.ballerina.runtime.internal.types.BFutureType; +import io.ballerina.runtime.internal.util.StringUtils; + +import java.util.Map; +import java.util.StringJoiner; + +/** + *

+ * Represent a Ballerina future in Java. + *

+ *

+ * Note: This is an internal API and may change in future versions. + *

+ * + * @since 0.995.0 + */ +public class FutureValue implements BFuture, RefValue { + + private BTypedesc typedesc; + + public Strand strand; + + public Object result; + + public boolean isDone; + + public Throwable panic; + + public Callback callback; + + private boolean waited; + + Type type; + + @Deprecated + public FutureValue(Strand strand, Callback callback, Type constraint) { + this.strand = strand; + this.callback = callback; + this.type = new BFutureType(constraint); + } + + @Override + public String stringValue(BLink parent) { + StringJoiner sj = new StringJoiner(",", "{", "}"); + sj.add("isDone:" + isDone); + if (isDone) { + sj.add("result:" + StringUtils.getStringVal(result, parent)); + } + if (panic != null) { + sj.add("panic:" + panic.getLocalizedMessage()); + } + return "future " + sj; + } + + @Override + public String expressionStringValue(BLink parent) { + return stringValue(parent); + } + + @Override + public Type getType() { + return this.type; + } + + @Override + public Object copy(Map refs) { + throw new UnsupportedOperationException(); + } + + @Override + public Object frozenCopy(Map refs) { + throw new UnsupportedOperationException(); + } + + @Override + public BTypedesc getTypedesc() { + if (this.typedesc == null) { + this.typedesc = new TypedescValueImpl(this.type); + } + return typedesc; + } + + @Override + public void cancel() { + this.strand.cancel = true; + } + + /** + * Returns the strand that the future is attached to. + * @return {@code Strand} + */ + @Override + public Strand getStrand() { + return this.strand; + } + + /** + * Returns the result value of the future. + * @return result value + */ + @Override + public Object getResult() { + return this.result; + } + + /** + * Returns completion status of the {@code Strand} that the future is attached. + * @return true if future is completed + */ + @Override + public boolean isDone() { + return this.isDone; + } + + /** + * Returns {@code Throwable} if the attached strand panic. + * @return panic error or null if not panic occurred + */ + @Override + public Throwable getPanic() { + return this.panic; + } + + /** + * {@code CallableUnitCallback} listening on the completion of this future. + * @return registered {@code CallableUnitCallback} + */ + @Override + public Callback getCallback() { + return this.callback; + } + + @Override + public String toString() { + return stringValue(null); + } + + public boolean hasWaited() { + return waited; + } + + public void setWaited(boolean waited) { + this.waited = waited; + } +} diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/HandleValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/HandleValue.java index f41b50630709..42f5ce5c100f 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/HandleValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/HandleValue.java @@ -37,7 +37,7 @@ */ public class HandleValue implements BHandle, RefValue { - private Object value; + private final Object value; private BTypedesc typedesc; public HandleValue(Object value) { @@ -48,6 +48,7 @@ public HandleValue(Object value) { * Returns the internal value of the handle. * @return {@code Object} value */ + @Override public Object getValue() { return value; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/IteratorValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/IteratorValue.java index 924748e14728..8004a431ad5f 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/IteratorValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/IteratorValue.java @@ -34,8 +34,9 @@ *

* * @since 0.995.0 + * @param Type of the value returned by the iterator */ -public interface IteratorValue extends RefValue, BIterator { +public interface IteratorValue extends RefValue, BIterator { BTypedesc TYPEDESC = new TypedescValueImpl(PredefinedTypes.TYPE_ITERATOR); diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/MapValueImpl.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/MapValueImpl.java index 87ad34d427a4..53b0e46f92f2 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/MapValueImpl.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/MapValueImpl.java @@ -95,7 +95,6 @@ public class MapValueImpl extends LinkedHashMap implements RefValue, CollectionValue, MapValue, BMap { - private static final long serialVersionUID = 1L; private BTypedesc typedesc; private Type type; private Type referredType; @@ -128,10 +127,11 @@ public MapValueImpl() { this.referredType = this.type; } + @Override public Long getIntValue(BString key) { Object value = get(key); - if (value instanceof Integer) { // field is an int subtype - return ((Integer) value).longValue(); + if (value instanceof Integer i) { // field is an int subtype + return i.longValue(); } return (Long) value; } @@ -148,30 +148,37 @@ public boolean getUnboxedBooleanValue(BString key) { return getBooleanValue(key); } + @Override public Double getFloatValue(BString key) { return (Double) get(key); } + @Override public BString getStringValue(BString key) { return (BString) get(key); } + @Override public Boolean getBooleanValue(BString key) { return (Boolean) get(key); } + @Override public BMap getMapValue(BString key) { return (BMap) get(key); } + @Override public BObject getObjectValue(BString key) { return (BObject) get(key); } + @Override public BArray getArrayValue(BString key) { return (BArray) get(key); } + @Override public long getDefaultableIntValue(BString key) { if (get(key) != null) { return getIntValue(key); @@ -186,6 +193,7 @@ public long getDefaultableIntValue(BString key) { * @param key key used to get the value * @return value associated with the key */ + @Override public V getOrThrow(Object key) { if (!containsKey(key)) { throw ErrorCreator.createError(MAP_KEY_NOT_FOUND_ERROR, @@ -202,6 +210,7 @@ public V getOrThrow(Object key) { * @param key key used to get the value * @return value associated with the key */ + @Override public V fillAndGet(Object key) { if (containsKey(key)) { return this.get(key); @@ -212,7 +221,7 @@ public V fillAndGet(Object key) { // The type should be a record or map for filling read. if (this.referredType.getTag() == TypeTags.RECORD_TYPE_TAG) { BRecordType recordType = (BRecordType) this.referredType; - Map fields = recordType.getFields(); + Map fields = recordType.getFields(); if (fields.containsKey(key.toString())) { expectedType = ((BField) fields.get(key.toString())).getFieldType(); } else { @@ -239,7 +248,7 @@ public V fillAndGet(Object key) { } @Override - public Object merge(BMap v2, boolean checkMergeability) { + public Object merge(BMap v2, boolean checkMergeability) { if (checkMergeability) { BError errorIfUnmergeable = JsonInternalUtils.getErrorIfUnmergeable(this, v2, new ArrayList<>()); if (errorIfUnmergeable != null) { @@ -273,10 +282,10 @@ public Object merge(BMap v2, boolean checkMergeability) { * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key - * @return the previous value associated with key, or - * null if there was no mapping for key. - * (A null return can also indicate that the map - * previously associated null with key.) + * @return the previous value associated with {@code key}, or + * {@code null} if there was no mapping for {@code key}. + * (A {@code null} return can also indicate that the map + * previously associated {@code null} with {@code key}.) */ @Override public V put(K key, V value) { @@ -284,18 +293,13 @@ public V put(K key, V value) { return putValue(key, value); } - String errMessage = ""; - switch (getImpliedType(getType()).getTag()) { - case TypeTags.RECORD_TYPE_TAG: - errMessage = "Invalid update of record field: "; - break; - case TypeTags.MAP_TAG: - errMessage = "Invalid map insertion: "; - break; - } + String errMessage = switch (getImpliedType(getType()).getTag()) { + case TypeTags.RECORD_TYPE_TAG -> "Invalid update of record field: "; + case TypeTags.MAP_TAG -> "Invalid map insertion: "; + default -> ""; + }; throw ErrorCreator.createError(getModulePrefixedReason(MAP_LANG_LIB, INVALID_UPDATE_ERROR_IDENTIFIER), - StringUtils - .fromString(errMessage).concat(ErrorHelper.getErrorMessage( + StringUtils.fromString(errMessage).concat(ErrorHelper.getErrorMessage( INVALID_READONLY_VALUE_UPDATE))); } @@ -340,6 +344,7 @@ protected void populateInitialValues(BMapInitialValueEntry[] initialValues) { } } + @Override public void populateInitialValue(K key, V value) { if (referredType.getTag() == TypeTags.MAP_TAG) { MapUtils.handleInherentTypeViolatingMapUpdate(value, (BMapType) referredType); @@ -356,6 +361,7 @@ public void populateInitialValue(K key, V value) { /** * Clear map entries. */ + @Override public void clear() { validateFreezeStatus(); super.clear(); @@ -438,6 +444,7 @@ public V remove(Object key) { * * @return keys as an array */ + @Override @SuppressWarnings("unchecked") public K[] getKeys() { Set keys = super.keySet(); @@ -455,6 +462,7 @@ public K[] getKeys() { * * @return values as an array */ + @Override public Collection values() { return super.values(); } @@ -474,6 +482,7 @@ public int size() { * * @return Flag indicating whether the map is empty or not */ + @Override public boolean isEmpty() { return this.size() == 0; } @@ -576,8 +585,8 @@ public void freezeDirect() { this.referredType = ReadOnlyUtils.setImmutableTypeAndGetEffectiveType(this.referredType); this.values().forEach(val -> { - if (val instanceof BRefValue) { - ((BRefValue) val).freezeDirect(); + if (val instanceof BRefValue bRefValue) { + bRefValue.freezeDirect(); } }); this.typedesc = null; @@ -596,7 +605,7 @@ public String getJSONString() { } @Override - public IteratorValue getIterator() { + public IteratorValue getIterator() { return new MapIterator<>(new LinkedHashSet<>(this.entrySet()).iterator()); } @@ -608,7 +617,7 @@ public IteratorValue getIterator() { * * @since 0.995.0 */ - static class MapIterator implements IteratorValue { + static class MapIterator implements IteratorValue { Iterator> iterator; @@ -644,6 +653,7 @@ public boolean hasNext() { * @param key key to identify native value. * @param data value to be added. */ + @Override public void addNativeData(String key, Object data) { nativeData.put(key, data); } @@ -653,6 +663,7 @@ public void addNativeData(String key, Object data) { * @param key key to identify native value. * @return value for the given key. */ + @Override public Object getNativeData(String key) { return nativeData.get(key); } @@ -695,6 +706,7 @@ private void initializeIteratorNextReturnType() { iteratorNextReturnType = IteratorUtils.createIteratorNextReturnType(type); } + @Override public Type getIteratorNextReturnType() { if (iteratorNextReturnType == null) { initializeIteratorNextReturnType(); diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/MappingInitialValueEntry.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/MappingInitialValueEntry.java index 5309a25d3919..3c51b8df6ed6 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/MappingInitialValueEntry.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/MappingInitialValueEntry.java @@ -28,6 +28,7 @@ */ public abstract class MappingInitialValueEntry implements BMapInitialValueEntry { + @Override public boolean isKeyValueEntry() { return true; } @@ -55,9 +56,9 @@ public KeyValueEntry(Object key, Object value) { */ public static class SpreadFieldEntry extends MappingInitialValueEntry { - public BMap values; + public BMap values; - public SpreadFieldEntry(BMap mappingValue) { + public SpreadFieldEntry(BMap mappingValue) { this.values = mappingValue; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/NonBmpStringValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/NonBmpStringValue.java index 38e4dc50cb6e..2210dfa05257 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/NonBmpStringValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/NonBmpStringValue.java @@ -1,131 +1,131 @@ - /* - * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. 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.runtime.internal.values; +/* + * Copyright (c) 2019, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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.runtime.internal.values; - import io.ballerina.runtime.api.utils.StringUtils; +import io.ballerina.runtime.api.utils.StringUtils; import io.ballerina.runtime.api.values.BString; import java.util.Arrays; - /** - * Represent ballerina strings containing at least one non basic multilingual plane unicode character. - * - * @since 1.0.5 - */ - public class NonBmpStringValue extends StringValue { +/** + * Represent ballerina strings containing at least one non basic multilingual plane unicode character. + * + * @since 1.0.5 + */ +public class NonBmpStringValue extends StringValue { - private final int[] surrogates; + private final int[] surrogates; - public NonBmpStringValue(String value, int[] surrogatePairLocations) { - super(value, true); - surrogates = surrogatePairLocations; - } + public NonBmpStringValue(String value, int[] surrogatePairLocations) { + super(value, true); + surrogates = surrogatePairLocations; + } + + @Override + public int getCodePoint(int index) { + if ((index < 0) || (index >= value.length() - surrogates.length)) { + throw new StringIndexOutOfBoundsException(index); + } + + int offset = index; + for (int surrogate : surrogates) { + if (surrogate < index) { + offset++; + } else if (surrogate > index) { + break; + } else { + return Character.toCodePoint(value.charAt(offset), value.charAt(offset + 1)); + } + } + return value.charAt(offset); + } + + @Override + public int length() { + return value.length() - surrogates.length; + } + + @Override + public BString concat(BString str) { + StringValue stringValue = (StringValue) str; + if (stringValue.isNonBmp) { + NonBmpStringValue other = (NonBmpStringValue) str; + int[] both = Arrays.copyOf(surrogates, surrogates.length + other.surrogates.length); + int length = length(); + for (int i = 0; i < other.surrogates.length; i++) { + both[i + surrogates.length] = other.surrogates[i] + length; + } + return new NonBmpStringValue(this.value + other.value, both); + } + return new NonBmpStringValue(this.value + str.getValue(), surrogates); + } + + public int[] getSurrogates() { + return surrogates.clone(); + } @Override - public int getCodePoint(int index) { - if ((index < 0) || (index >= value.length() - surrogates.length)) { - throw new StringIndexOutOfBoundsException(index); + public Long indexOf(BString str, int fromIndex) { + int offset = getOffset(fromIndex); + long index = value.indexOf(str.getValue(), offset); + if (index < 0) { + return null; } - - int offset = index; - for (int surrogate : surrogates) { - if (surrogate < index) { - offset++; - } else if (surrogate > index) { - break; - } else { - return Character.toCodePoint(value.charAt(offset), value.charAt(offset + 1)); + for (int i = 0; i < index; i++) { + char c = value.charAt(i); + if (Character.isHighSurrogate(c)) { + index--; } } - return value.charAt(offset); + return index; } @Override - public int length() { - return value.length() - surrogates.length; + public Long lastIndexOf(BString str, int fromIndex) { + int offset = getOffset(fromIndex); + long index = value.lastIndexOf(str.getValue(), offset); + if (index < 0) { + return null; + } + for (int i = 0; i < index; i++) { + char c = value.charAt(i); + if (Character.isHighSurrogate(c)) { + index--; + } + } + return index; + } + @Override + public BString substring(int beginIndex, int endIndex) { + int beginOffset = getOffset(beginIndex); + int endOffset = getOffset(endIndex); + return StringUtils.fromString(value.substring(beginOffset, endOffset)); } - @Override - public BString concat(BString str) { - StringValue stringValue = (StringValue) str; - if (stringValue.isNonBmp) { - NonBmpStringValue other = (NonBmpStringValue) str; - int[] both = Arrays.copyOf(surrogates, surrogates.length + other.surrogates.length); - int length = length(); - for (int i = 0; i < other.surrogates.length; i++) { - both[i + surrogates.length] = other.surrogates[i] + length; + private int getOffset(int fromIndex) { + int offset = fromIndex; + for (int surrogate : surrogates) { + if (surrogate < fromIndex) { + offset++; + } else { + break; } - return new NonBmpStringValue(this.value + other.value, both); } - return new NonBmpStringValue(this.value + str.getValue(), surrogates); + return offset; } - - public int[] getSurrogates() { - return surrogates.clone(); - } - - @Override - public Long indexOf(BString str, int fromIndex) { - int offset = getOffset(fromIndex); - long index = value.indexOf(str.getValue(), offset); - if (index < 0) { - return null; - } - for (int i = 0; i < index; i++) { - char c = value.charAt(i); - if (Character.isHighSurrogate(c)) { - index--; - } - } - return index; - } - - @Override - public Long lastIndexOf(BString str, int fromIndex) { - int offset = getOffset(fromIndex); - long index = value.lastIndexOf(str.getValue(), offset); - if (index < 0) { - return null; - } - for (int i = 0; i < index; i++) { - char c = value.charAt(i); - if (Character.isHighSurrogate(c)) { - index--; - } - } - return index; - } - @Override - public BString substring(int beginIndex, int endIndex) { - int beginOffset = getOffset(beginIndex); - int endOffset = getOffset(endIndex); - return StringUtils.fromString(value.substring(beginOffset, endOffset)); - } - - private int getOffset(int fromIndex) { - int offset = fromIndex; - for (int surrogate : surrogates) { - if (surrogate < fromIndex) { - offset++; - } else { - break; - } - } - return offset; - } - } +} diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ObjectValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ObjectValue.java index 2dbe41561ef1..6a2116b51041 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ObjectValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ObjectValue.java @@ -33,7 +33,9 @@ */ public interface ObjectValue extends BObject { + @Override Object call(Strand strand, String funcName, Object... args); + @Override BFuture start(Strand strand, String funcName, Object... args); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ReadOnlyUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ReadOnlyUtils.java index 5e527b31679f..9b46eba3d30c 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ReadOnlyUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/ReadOnlyUtils.java @@ -66,7 +66,7 @@ * * @since 1.3.0 */ -public class ReadOnlyUtils { +public final class ReadOnlyUtils { /** * Method to handle an update to a value, that is invalid due to the value being immutable. @@ -224,8 +224,8 @@ private static BIntersectionType setImmutableIntersectionType(Type type, Set entry : originalFields.entrySet()) { Field originalField = entry.getValue(); fields.put(entry.getKey(), - new BField(getImmutableType(originalField.getFieldType(), unresolvedTypes), - originalField.getFieldName(), originalField.getFlags())); + new BField(getImmutableType(originalField.getFieldType(), unresolvedTypes), + originalField.getFieldName(), originalField.getFlags() | SymbolFlags.READONLY)); } BRecordType immutableRecordType = new BRecordType( diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpAtomQuantifier.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpAtomQuantifier.java index 2ca954b78553..21a3bef34c66 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpAtomQuantifier.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpAtomQuantifier.java @@ -61,8 +61,8 @@ public void setReQuantifier(RegExpQuantifier reQuantifier) { private Object getValidReAtom(Object reAtom) { // If reAtom is an instance of BString it's an insertion. Hence, we need to parse it and check whether it's a // valid insertion. - if (reAtom instanceof BString) { - validateInsertion((BString) reAtom); + if (reAtom instanceof BString bString) { + validateInsertion(bString); } return reAtom; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpCharSet.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpCharSet.java index 79d1e2612697..ff1b4d75f9a7 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpCharSet.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpCharSet.java @@ -49,8 +49,8 @@ private Object[] getCharSetAtomsList(ArrayValue charSetAtoms) { Object[] atoms = new Object[size]; for (int i = 0; i < size; i++) { Object atom = charSetAtoms.get(i); - if (atom instanceof BString) { - atoms[i] = ((BString) atom).getValue(); + if (atom instanceof BString bString) { + atoms[i] = bString.getValue(); continue; } atoms[i] = atom; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpCharSetRange.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpCharSetRange.java index 9a25df276e46..3cb0e6d121de 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpCharSetRange.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpCharSetRange.java @@ -31,7 +31,7 @@ */ public class RegExpCharSetRange extends RegExpCommonValue { private String lhsCharSetAtom; - private String dash; + private final String dash; private String rhsCharSetAom; public RegExpCharSetRange(String lhsCharSetAtom, String dash, String rhsCharSetAom) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpCharacterClass.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpCharacterClass.java index 057cab178ffe..064dd5d56502 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpCharacterClass.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpCharacterClass.java @@ -31,7 +31,7 @@ */ public class RegExpCharacterClass extends RegExpCommonValue implements RegExpAtom { private String characterClassStart; - private String negation; + private final String negation; private RegExpCharSet reCharSet; private String characterClassEnd; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpDisjunction.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpDisjunction.java index 96f0cbfb0cf5..54cde1be1df8 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpDisjunction.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpDisjunction.java @@ -55,8 +55,8 @@ public String stringValue(BLink parent) { if (t == null) { break; } - if (t instanceof String) { - terms.add(((String) t)); + if (t instanceof String s) { + terms.add(s); continue; } terms.add(getStringVal(t, parent)); diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpValue.java index 7c8df5ed7130..da45d3856a1e 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/RegExpValue.java @@ -46,6 +46,7 @@ public RegExpValue(RegExpDisjunction regExpDisjunction) { this.regExpDisjunction = regExpDisjunction; } + @Override public RegExpDisjunction getRegExpDisjunction() { return this.regExpDisjunction; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/StreamValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/StreamValue.java index a0cb54eb1ff6..bf0eb2d4a2ca 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/StreamValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/StreamValue.java @@ -42,11 +42,11 @@ public class StreamValue implements RefValue, BStream { private BTypedesc typedesc; - private Type type; - private Type constraintType; - private Type completionType; + private final Type type; + private final Type constraintType; + private final Type completionType; private Type iteratorNextReturnType; - private BObject iteratorObj; + private final BObject iteratorObj; /** @@ -75,6 +75,7 @@ public String getStreamId() { return streamId; } + @Override public BObject getIteratorObj() { return iteratorObj; } @@ -91,6 +92,7 @@ public Type getIteratorNextReturnType() { * {@inheritDoc} * @param parent The link to the parent node */ + @Override public String stringValue(BLink parent) { return getType().toString(); } @@ -99,6 +101,7 @@ public String stringValue(BLink parent) { * {@inheritDoc} * @param parent The link to the parent node */ + @Override public String expressionStringValue(BLink parent) { return stringValue(parent); } @@ -116,6 +119,7 @@ public Object copy(Map refs) { /** * {@inheritDoc} */ + @Override public Object frozenCopy(Map refs) { throw new UnsupportedOperationException(); } @@ -128,10 +132,12 @@ public BTypedesc getTypedesc() { return this.typedesc; } + @Override public Type getConstraintType() { return constraintType; } + @Override public Type getCompletionType() { return completionType; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/StreamingJsonValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/StreamingJsonValue.java index 944d7ed19579..e532436f0c9e 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/StreamingJsonValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/StreamingJsonValue.java @@ -114,6 +114,7 @@ public void serialize(JsonGenerator gen) { * Serialize the value to given {@code Writer}. * @param writer {@code Writer} to be used */ + @Override public void serialize(Writer writer) { try (JsonGenerator gen = new JsonGenerator(writer)) { serialize(gen); @@ -199,7 +200,7 @@ private void buildDatasource() { } @Override - public IteratorValue getIterator() { + public IteratorValue getIterator() { return new ArrayIterator(this); } @@ -208,7 +209,7 @@ public IteratorValue getIterator() { * * @since 0.995.0 */ - static class StreamingJsonIterator implements IteratorValue { + static class StreamingJsonIterator implements IteratorValue { StreamingJsonValue array; long cursor = 0; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/StringValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/StringValue.java index a00c1c0e0575..a96fcacd5a07 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/StringValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/StringValue.java @@ -55,7 +55,7 @@ public Object frozenCopy(Map refs) { } @Override - public IteratorValue getIterator() { + public IteratorValue getIterator() { return new CharIterator(this); } @@ -94,8 +94,8 @@ public boolean equals(Object str) { if (str == this) { return true; } - if (str instanceof BString) { - return ((BString) str).getValue().equals(value); + if (str instanceof BString bString) { + return bString.getValue().equals(value); } return false; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TableValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TableValue.java index 6cffe98832d4..108be2af95a2 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TableValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TableValue.java @@ -34,13 +34,18 @@ */ public interface TableValue extends RefValue, CollectionValue, BTable { + @Override void add(V data); + @Override V getOrThrow(Object key); + @Override V put(K key, V value); + @Override long getNextKey(); + @Override Type getKeyType(); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TableValueImpl.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TableValueImpl.java index d26fe7ce9db4..305586506362 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TableValueImpl.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TableValueImpl.java @@ -89,16 +89,16 @@ public class TableValueImpl implements TableValue { private Type type; private TableType tableType; private Type iteratorNextReturnType; - private ConcurrentHashMap>> entries; - private LinkedHashMap> values; + private final ConcurrentHashMap>> entries; + private final LinkedHashMap> values; private String[] fieldNames; private ValueHolder valueHolder; private long maxIntKey = 0; //These are required to achieve the iterator behavior - private Map indexToKeyMap; - private Map keyToIndexMap; - private Map keyValues; + private final Map indexToKeyMap; + private final Map keyToIndexMap; + private final Map keyValues; private long noOfAddedEntries = 0; private boolean nextKeySupported; @@ -149,7 +149,7 @@ public TableValueImpl(TableType tableType, ArrayValue fieldNames) { } private void addData(ArrayValue data) { - BIterator itr = data.getIterator(); + BIterator itr = data.getIterator(); while (itr.hasNext()) { Object next = itr.next(); valueHolder.addData((V) next); @@ -157,7 +157,7 @@ private void addData(ArrayValue data) { } @Override - public IteratorValue getIterator() { + public IteratorValue getIterator() { return new TableIterator(); } @@ -178,7 +178,7 @@ public Object copy(Map refs) { clone.fieldNames = fieldNames; } - IteratorValue itr = getIterator(); + IteratorValue itr = getIterator(); while (itr.hasNext()) { TupleValueImpl tupleValue = (TupleValueImpl) itr.next(); Object value = tupleValue.get(1); @@ -220,6 +220,7 @@ public V get(Object key) { } //Generates the key from the given data + @Override public V put(V value) { handleFrozenTableValue(); return valueHolder.putData(value); @@ -254,7 +255,7 @@ public Set> entrySet() { for (List> entry: entries.values()) { entrySet.addAll(entry); } - return new LinkedHashSet(entries.values()); + return entrySet; } @Override @@ -286,6 +287,7 @@ public V getOrThrow(Object key) { return this.get(key); } + @Override public V removeOrThrow(Object key) { handleFrozenTableValue(); if (!containsKey(key)) { @@ -295,6 +297,7 @@ public V removeOrThrow(Object key) { return this.remove(key); } + @Override public long getNextKey() { if (!nextKeySupported) { throw ErrorCreator.createError(OPERATION_NOT_SUPPORTED_ERROR, @@ -303,9 +306,10 @@ public long getNextKey() { + "The key sequence should only have an " + "Integer field.")); } - return indexToKeyMap.size() == 0 ? 0 : (this.maxIntKey + 1); + return indexToKeyMap.isEmpty() ? 0 : (this.maxIntKey + 1); } + @Override public Type getKeyType() { return this.valueHolder.getKeyType(); } @@ -368,6 +372,7 @@ public void freezeDirect() { this.typedesc = null; } + @Override public String stringValue(BLink parent) { Iterator>> itr = values.entrySet().iterator(); return createStringValueDataEntry(itr, parent); @@ -405,8 +410,8 @@ private String createExpressionStringValueDataEntry(Iterator> struct = itr.next(); @@ -455,6 +460,7 @@ public Type getType() { return this.type; } + @Override public Type getIteratorNextReturnType() { if (iteratorNextReturnType == null) { iteratorNextReturnType = IteratorUtils.createIteratorNextReturnType(tableType.getConstrainedType()); @@ -504,7 +510,7 @@ public boolean equals(Object o, Set visitedValues) { return true; } - private class TableIterator implements IteratorValue { + private class TableIterator implements IteratorValue { private long cursor; TableIterator() { @@ -535,7 +541,7 @@ public Object next() { @Override public boolean hasNext() { - return cursor < noOfAddedEntries && values.size() != 0; + return cursor < noOfAddedEntries && !values.isEmpty(); } } @@ -556,12 +562,12 @@ public V putData(K key, V data) { } public V putData(V data) { - checkInherentTypeViolation((MapValue) data, tableType); + checkInherentTypeViolation((MapValue) data, tableType); ArrayList newData = new ArrayList<>(); newData.add(data); - Map.Entry entry = new AbstractMap.SimpleEntry(data, data); + Map.Entry entry = new AbstractMap.SimpleEntry<>((K) data, data); List> entryList = new ArrayList<>(); entryList.add(entry); UUID uuid = UUID.randomUUID(); @@ -588,7 +594,7 @@ public Type getKeyType() { } private class KeyHashValueHolder extends ValueHolder { - private DefaultKeyWrapper keyWrapper; + private final DefaultKeyWrapper keyWrapper; private Type keyType; public KeyHashValueHolder() { @@ -600,21 +606,22 @@ public KeyHashValueHolder() { } } + @Override public void addData(V data) { - MapValue dataMap = (MapValue) data; + MapValue dataMap = (MapValue) data; checkInherentTypeViolation(dataMap, tableType); K key = this.keyWrapper.wrapKey(dataMap); - if (containsKey((K) key)) { + if (containsKey(key)) { throw ErrorCreator.createError(TABLE_HAS_A_VALUE_FOR_KEY_ERROR, ErrorHelper.getErrorDetails(ErrorCodes.TABLE_HAS_A_VALUE_FOR_KEY, key)); } - if (nextKeySupported && (indexToKeyMap.size() == 0 || maxIntKey < TypeChecker.anyToInt(key))) { + if (nextKeySupported && (indexToKeyMap.isEmpty() || maxIntKey < TypeChecker.anyToInt(key))) { maxIntKey = ((Long) TypeChecker.anyToInt(key)).intValue(); } - Map.Entry entry = new AbstractMap.SimpleEntry(key, data); + Map.Entry entry = new AbstractMap.SimpleEntry<>(key, data); Long hash = TableUtils.hash(key, null); if (entries.containsKey(hash)) { @@ -629,6 +636,7 @@ public void addData(V data) { putNewData(key, data, entry, hash); } + @Override public V getData(K key) { List> entryList = entries.get(TableUtils.hash(key, null)); if (entryList == null) { @@ -642,9 +650,10 @@ public V getData(K key) { return null; } + @Override public V putData(K key, V data) { - Map.Entry entry = new AbstractMap.SimpleEntry(key, data); - Object actualKey = this.keyWrapper.wrapKey((MapValue) data); + Map.Entry entry = new AbstractMap.SimpleEntry<>(key, data); + Object actualKey = this.keyWrapper.wrapKey((MapValue) data); Long actualHash = TableUtils.hash(actualKey, null); Long hash = TableUtils.hash(key, null); @@ -670,8 +679,9 @@ private V putNewData(K key, V value, Map.Entry entry, Long hash) { return data.get(0); } + @Override public V putData(V data) { - MapValue dataMap = (MapValue) data; + MapValue dataMap = (MapValue) data; checkInherentTypeViolation(dataMap, tableType); K key = this.keyWrapper.wrapKey(dataMap); Map.Entry entry = new AbstractMap.SimpleEntry<>(key, data); @@ -680,7 +690,7 @@ public V putData(V data) { if (entries.containsKey(hash)) { return updateExistingEntry(key, data, entry, hash); } - return putNewData((K) key, data, entry, hash); + return putNewData(key, data, entry, hash); } private V updateExistingEntry(K key, V data, Map.Entry entry, Long hash) { @@ -700,6 +710,7 @@ private V updateExistingEntry(K key, V data, Map.Entry entry, Long hash) { return data; } + @Override public V remove(K key) { keyValues.remove(key); Long hash = TableUtils.hash(key, null); @@ -734,6 +745,7 @@ public V remove(K key) { return removedValue.get(0); } + @Override public boolean containsKey(K key) { if (entries.containsKey(TableUtils.hash(key, null))) { List> entryList = entries.get(TableUtils.hash(key, null)); @@ -746,6 +758,7 @@ public boolean containsKey(K key) { return false; } + @Override public Type getKeyType() { return keyType; } @@ -761,7 +774,7 @@ public DefaultKeyWrapper() { } } - public K wrapKey(MapValue data) { + public K wrapKey(MapValue data) { return (K) data.get(StringUtils.fromString(fieldNames[0])); } } @@ -783,7 +796,8 @@ public MultiKeyWrapper() { keyType = new BTupleType(keyTypes); } - public K wrapKey(MapValue data) { + @Override + public K wrapKey(MapValue data) { TupleValueImpl arr = (TupleValueImpl) ValueCreator .createTupleValue((BTupleType) keyType); for (int i = 0; i < fieldNames.length; i++) { @@ -816,7 +830,7 @@ private void updateIndexKeyMappings(Long hash, K key, V value) { } // This method checks for inherent table type violation - private void checkInherentTypeViolation(MapValue dataMap, TableType type) { + private void checkInherentTypeViolation(MapValue dataMap, TableType type) { if (!TypeChecker.checkIsType(dataMap.getType(), type.getConstrainedType())) { BString reason = getModulePrefixedReason(TABLE_LANG_LIB, INHERENT_TYPE_VIOLATION_ERROR_IDENTIFIER); BString detail = StringUtils.fromString("value type '" + dataMap.getType() + "' inconsistent with the " + diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TupleValueImpl.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TupleValueImpl.java index d0939c5f7158..922b1ce59a21 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TupleValueImpl.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TupleValueImpl.java @@ -51,6 +51,7 @@ import static io.ballerina.runtime.internal.ValueUtils.getTypedescValue; import static io.ballerina.runtime.internal.errors.ErrorReasons.INDEX_OUT_OF_RANGE_ERROR_IDENTIFIER; import static io.ballerina.runtime.internal.errors.ErrorReasons.INHERENT_TYPE_VIOLATION_ERROR_IDENTIFIER; +import static io.ballerina.runtime.internal.errors.ErrorReasons.OPERATION_NOT_SUPPORTED_IDENTIFIER; import static io.ballerina.runtime.internal.errors.ErrorReasons.getModulePrefixedReason; import static io.ballerina.runtime.internal.util.StringUtils.getExpressionStringVal; import static io.ballerina.runtime.internal.util.StringUtils.getStringVal; @@ -251,6 +252,7 @@ public long getInt(long index) { * @param index array index * @return array element */ + @Override public boolean getBoolean(long index) { return (Boolean) get(index); } @@ -264,8 +266,8 @@ public boolean getBoolean(long index) { @Override public byte getByte(long index) { Object value = get(index); - if (value instanceof Long) { - return ((Long) value).byteValue(); + if (value instanceof Long l) { + return l.byteValue(); } return (Byte) value; } @@ -421,7 +423,22 @@ public void append(Object value) { @Override public Object shift(long index) { + return shift(index, "shift"); + } + + @Override + public Object pop(long index) { + return shift(index, "pop"); + } + + @Override + public Object remove(long index) { + return shift(index, "remove"); + } + + public Object shift(long index, String operation) { handleImmutableArrayValue(); + validateTupleSizeAndInherentType((int) index, operation); Object val = get(index); shiftArray((int) index); return val; @@ -515,8 +532,8 @@ public Object copy(Map refs) { refs.put(this, refValueArray); IntStream.range(0, this.size).forEach(i -> { Object value = this.refValues[i]; - if (value instanceof BRefValue) { - values[i] = ((BRefValue) value).copy(refs); + if (value instanceof BRefValue bRefValue) { + values[i] = bRefValue.copy(refs); } else { values[i] = value; } @@ -602,8 +619,8 @@ public void freezeDirect() { this.tupleType = (TupleType) TypeUtils.getImpliedType(type); for (int i = 0; i < this.size; i++) { Object value = this.get(i); - if (value instanceof BRefValue) { - ((BRefValue) value).freezeDirect(); + if (value instanceof BRefValue bRefValue) { + bRefValue.freezeDirect(); } } this.typedesc = null; @@ -613,7 +630,7 @@ public void freezeDirect() { * {@inheritDoc} */ @Override - public IteratorValue getIterator() { + public IteratorValue getIterator() { return new ArrayIterator(this); } @@ -652,24 +669,21 @@ protected void fillValues(int index) { protected void rangeCheckForGet(long index, int size) { rangeCheck(index, size); if (index < 0 || index >= size) { - throw ErrorHelper.getRuntimeException( - getModulePrefixedReason(ARRAY_LANG_LIB, INDEX_OUT_OF_RANGE_ERROR_IDENTIFIER), - ErrorCodes.TUPLE_INDEX_OUT_OF_RANGE, index, size); + throw ErrorHelper.getRuntimeException(getModulePrefixedReason(ARRAY_LANG_LIB, + INDEX_OUT_OF_RANGE_ERROR_IDENTIFIER), ErrorCodes.TUPLE_INDEX_OUT_OF_RANGE, index, size); } } @Override protected void rangeCheck(long index, int size) { if (index > Integer.MAX_VALUE || index < Integer.MIN_VALUE) { - throw ErrorHelper.getRuntimeException( - getModulePrefixedReason(ARRAY_LANG_LIB, INDEX_OUT_OF_RANGE_ERROR_IDENTIFIER), - ErrorCodes.INDEX_NUMBER_TOO_LARGE, index); + throw ErrorHelper.getRuntimeException(getModulePrefixedReason(ARRAY_LANG_LIB, + INDEX_OUT_OF_RANGE_ERROR_IDENTIFIER), ErrorCodes.INDEX_NUMBER_TOO_LARGE, index); } if ((this.tupleType.getRestType() == null && index >= this.maxSize) || (int) index < 0) { - throw ErrorHelper.getRuntimeException( - getModulePrefixedReason(ARRAY_LANG_LIB, INDEX_OUT_OF_RANGE_ERROR_IDENTIFIER), - ErrorCodes.TUPLE_INDEX_OUT_OF_RANGE, index, size); + throw ErrorHelper.getRuntimeException(getModulePrefixedReason(ARRAY_LANG_LIB, + INDEX_OUT_OF_RANGE_ERROR_IDENTIFIER), ErrorCodes.TUPLE_INDEX_OUT_OF_RANGE, index, size); } } @@ -724,12 +738,11 @@ protected void ensureCapacity(int requestedCapacity, int currentArraySize) { @Override protected void checkFixedLength(long length) { if (this.tupleType.getRestType() == null) { - throw ErrorHelper.getRuntimeException( - getModulePrefixedReason(ARRAY_LANG_LIB, INHERENT_TYPE_VIOLATION_ERROR_IDENTIFIER), - ErrorCodes.ILLEGAL_TUPLE_SIZE, size, length); + throw ErrorHelper.getRuntimeException(getModulePrefixedReason(ARRAY_LANG_LIB, + INHERENT_TYPE_VIOLATION_ERROR_IDENTIFIER), ErrorCodes.ILLEGAL_TUPLE_SIZE, size, length); } else if (this.tupleType.getTupleTypes().size() > length) { - throw ErrorHelper.getRuntimeException( - getModulePrefixedReason(ARRAY_LANG_LIB, INHERENT_TYPE_VIOLATION_ERROR_IDENTIFIER), + throw ErrorHelper.getRuntimeException(getModulePrefixedReason(ARRAY_LANG_LIB, + INHERENT_TYPE_VIOLATION_ERROR_IDENTIFIER), ErrorCodes.ILLEGAL_TUPLE_WITH_REST_TYPE_SIZE, this.tupleType.getTupleTypes().size(), length); } } @@ -737,6 +750,7 @@ protected void checkFixedLength(long length) { @Override protected void unshift(long index, Object[] vals) { handleImmutableArrayValue(); + validateInherentTypeOfExistingMembers((int) index, vals.length); unshiftArray(index, vals.length, getCurrentArrayLength()); addToRefArray(vals, (int) index); } @@ -756,10 +770,9 @@ private void prepareForAdd(long index, Object value, int currentArraySize) { } if (!TypeChecker.checkIsType(value, elemType)) { - throw ErrorCreator.createError( - getModulePrefixedReason(ARRAY_LANG_LIB, INHERENT_TYPE_VIOLATION_ERROR_IDENTIFIER), - ErrorHelper.getErrorDetails(ErrorCodes.INCOMPATIBLE_TYPE, elemType, - TypeChecker.getType(value))); + throw ErrorCreator.createError(getModulePrefixedReason(ARRAY_LANG_LIB, + INHERENT_TYPE_VIOLATION_ERROR_IDENTIFIER), + ErrorHelper.getErrorDetails(ErrorCodes.INCOMPATIBLE_TYPE, elemType, TypeChecker.getType(value))); } prepareForAddWithoutTypeCheck(currentArraySize, intIndex); @@ -806,16 +819,16 @@ private void addToRefArray(Object[] vals, int startIndex) { } private void unshiftArray(long index, int unshiftByN, int arrLength) { - int lastIndex = size() + unshiftByN - 1; + int currSize = size(); + int lastIndex = currSize + unshiftByN - 1; prepareForConsecutiveMultiAdd(lastIndex, arrLength); if (index > lastIndex) { - throw ErrorHelper.getRuntimeException( - getModulePrefixedReason(ARRAY_LANG_LIB, INDEX_OUT_OF_RANGE_ERROR_IDENTIFIER), - ErrorCodes.INDEX_NUMBER_TOO_LARGE, index); + throw ErrorHelper.getRuntimeException(getModulePrefixedReason(ARRAY_LANG_LIB, + INDEX_OUT_OF_RANGE_ERROR_IDENTIFIER), ErrorCodes.INDEX_NUMBER_TOO_LARGE, index); } int i = (int) index; - System.arraycopy(this.refValues, i, this.refValues, i + unshiftByN, this.size - i); + System.arraycopy(this.refValues, i, this.refValues, i + unshiftByN, currSize - i); } private int getCurrentArrayLength() { @@ -827,4 +840,35 @@ private void resetSize(int index) { size = index + 1; } } + + private void validateTupleSizeAndInherentType(int index, String operation) { + List tupleTypesList = this.tupleType.getTupleTypes(); + int numOfMandatoryTypes = tupleTypesList.size(); + if (numOfMandatoryTypes >= this.getLength()) { + throw ErrorHelper.getRuntimeException(getModulePrefixedReason(ARRAY_LANG_LIB, + OPERATION_NOT_SUPPORTED_IDENTIFIER), ErrorCodes.INVALID_TUPLE_MEMBER_SIZE, operation); + } + // Check if value belonging to i th type can be assigned to i-1 th type (Checking done by value, not type) + for (int i = index + 1; i <= numOfMandatoryTypes; i++) { + if (!TypeChecker.checkIsType(this.getRefValue(i), tupleTypesList.get(i - 1))) { + throw ErrorHelper.getRuntimeException(getModulePrefixedReason(ARRAY_LANG_LIB, + INHERENT_TYPE_VIOLATION_ERROR_IDENTIFIER), ErrorCodes.INCOMPATIBLE_TYPE, + tupleTypesList.get(i - 1), (i == numOfMandatoryTypes) ? + this.tupleType.getRestType() : tupleTypesList.get(i)); + } + } + } + + private void validateInherentTypeOfExistingMembers(int index, int offset) { + Type targetType; + for (int i = index; i < this.size; i++) { + targetType = (i + offset >= this.tupleType.getTupleTypes().size()) ? + this.tupleType.getRestType() : this.tupleType.getTupleTypes().get(i + offset); + if (!TypeChecker.checkIsType(this.getRefValue(i), targetType)) { + throw ErrorHelper.getRuntimeException(getModulePrefixedReason(ARRAY_LANG_LIB, + INHERENT_TYPE_VIOLATION_ERROR_IDENTIFIER), + ErrorCodes.INCOMPATIBLE_TYPE, TypeChecker.getType(this.getRefValue(i)), targetType); + } + } + } } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TypedescValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TypedescValue.java index 8fb9c222dce9..43810865770d 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TypedescValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TypedescValue.java @@ -29,7 +29,9 @@ */ public interface TypedescValue extends RefValue, BTypedesc { + @Override Object instantiate(Strand strand); + @Override Object instantiate(Strand strand, BInitialValueEntry[] initialValues); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TypedescValueImpl.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TypedescValueImpl.java index 6d014bcf16ed..39dc6347600a 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TypedescValueImpl.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/TypedescValueImpl.java @@ -25,6 +25,7 @@ import io.ballerina.runtime.api.values.BLink; import io.ballerina.runtime.api.values.BListInitialValueEntry; import io.ballerina.runtime.api.values.BMapInitialValueEntry; +import io.ballerina.runtime.api.values.BString; import io.ballerina.runtime.api.values.BTypedesc; import io.ballerina.runtime.internal.scheduling.Strand; import io.ballerina.runtime.internal.types.BAnnotatableType; @@ -53,24 +54,22 @@ public class TypedescValueImpl implements TypedescValue { final Type type; final Type describingType; // Type of the value describe by this typedesc. - public MapValue[] closures; - public MapValue annotations; + public MapValue[] closures; + public MapValue annotations; private BTypedesc typedesc; - @Deprecated public TypedescValueImpl(Type describingType) { this.type = new BTypedescType(describingType); this.describingType = describingType; } - @Deprecated - public TypedescValueImpl(Type describingType, MapValue[] closures) { + public TypedescValueImpl(Type describingType, MapValue[] closures) { this.type = new BTypedescType(describingType); this.describingType = describingType; this.closures = closures; } - public TypedescValueImpl(Type describingType, MapValue[] closures, MapValue annotations) { + public TypedescValueImpl(Type describingType, MapValue[] closures, MapValue annotations) { this(describingType, closures); this.annotations = annotations; ((BAnnotatableType) describingType).setAnnotations(annotations); @@ -80,6 +79,7 @@ public TypedescValueImpl(Type describingType, MapValue[] closures, MapValue anno * Returns the {@code BType} of the value describe by this type descriptor. * @return describing type */ + @Override public Type getDescribingType() { return describingType; } @@ -98,7 +98,7 @@ public Object instantiate(Strand s) { public Object instantiate(Strand s, BInitialValueEntry[] initialValues) { Type referredType = getImpliedType(this.describingType); if (referredType.getTag() == TypeTags.MAP_TAG) { - return new MapValueImpl(this.describingType, (BMapInitialValueEntry[]) initialValues); + return new MapValueImpl<>(this.describingType, (BMapInitialValueEntry[]) initialValues); } else if (referredType.getTag() == TypeTags.TUPLE_TAG) { return new TupleValueImpl(this.describingType, (BListInitialValueEntry[]) initialValues, this); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlComment.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlComment.java index 24725ac7bca8..00cab7fe4d6b 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlComment.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlComment.java @@ -47,9 +47,9 @@ public XmlComment(String data, boolean readonly) { } @Override - public IteratorValue getIterator() { + public IteratorValue getIterator() { XmlComment that = this; - return new IteratorValue() { + return new IteratorValue<>() { boolean read = false; @Override public boolean hasNext() { @@ -57,7 +57,7 @@ public boolean hasNext() { } @Override - public Object next() { + public XmlComment next() { if (!read) { this.read = true; return that; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlItem.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlItem.java index 72b91671e195..10d35118e3a2 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlItem.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlItem.java @@ -52,7 +52,6 @@ import javax.xml.XMLConstants; import javax.xml.namespace.QName; -import javax.xml.stream.XMLStreamException; import static io.ballerina.runtime.api.constants.RuntimeConstants.STRING_NULL_VALUE; import static io.ballerina.runtime.api.constants.RuntimeConstants.XML_LANG_LIB; @@ -71,9 +70,9 @@ public final class XmlItem extends XmlValue implements BXmlItem { private QName name; private XmlSequence children; - private AttributeMapValueImpl attributes; + private final AttributeMapValueImpl attributes; // Keep track of probable parents of xml element to detect probable cycles in xml. - private List> probableParents; + private final List> probableParents; public XmlItem(QName name, XmlSequence children, boolean readonly) { this.name = name; @@ -171,10 +170,12 @@ public String getElementName() { return name.toString(); } + @Override public QName getQName() { return this.name; } + @Override public void setQName(QName name) { this.name = name; } @@ -383,7 +384,7 @@ private BError createXMLCycleError() { StringUtils.fromString("Cycle detected")); } - private void mergeAdjoiningTextNodesIntoList(List leftList, List appendingList) { + private void mergeAdjoiningTextNodesIntoList(List leftList, List appendingList) { XmlText lastChild = (XmlText) leftList.get(leftList.size() - 1); String firstChildContent = appendingList.get(0).getTextValue(); String mergedTextContent = lastChild.getTextValue() + firstChildContent; @@ -445,7 +446,7 @@ public OMNode value() { return omElement; } catch (BError e) { throw e; - } catch (OMException | XMLStreamException e) { + } catch (OMException e) { Throwable cause = e.getCause() == null ? e : e.getCause(); throw ErrorCreator.createError(StringUtils.fromString((cause.getMessage()))); } catch (Throwable e) { @@ -507,8 +508,7 @@ public Object copy(Map refs) { MapValue attributesMap = xmlItem.getAttributesMap(); MapValue copy = (MapValue) this.getAttributesMap().copy(refs); - if (attributesMap instanceof MapValueImpl) { - MapValueImpl map = (MapValueImpl) attributesMap; + if (attributesMap instanceof MapValueImpl map) { map.putAll((Map) copy); } else { for (Map.Entry entry : copy.entrySet()) { @@ -537,6 +537,7 @@ public XmlValue getItem(int index) { ErrorCodes.XML_SEQUENCE_INDEX_OUT_OF_RANGE, 1, index); } + @Override public int size() { return 1; } @@ -587,7 +588,7 @@ public void removeChildren(String qname) { List toRemove = new ArrayList<>(); for (int i = 0; i < children.size(); i++) { BXml child = children.get(i); - if (child.getNodeType() == ELEMENT && ((XmlItem) child).getElementName().equals(qname)) { + if (child.getNodeType() == ELEMENT && child.getElementName().equals(qname)) { toRemove.add(i); } } @@ -654,14 +655,15 @@ private QName getQName(String localName, String namespaceUri, String prefix) { } } + @Override public BXmlSequence getChildrenSeq() { return children; } @Override - public IteratorValue getIterator() { + public IteratorValue getIterator() { XmlItem that = this; - return new IteratorValue() { + return new IteratorValue<>() { boolean read = false; @Override @@ -670,7 +672,7 @@ public boolean hasNext() { } @Override - public Object next() { + public XmlItem next() { if (read) { throw new NoSuchElementException(); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlNonElementItem.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlNonElementItem.java index 0a40cc982b3c..8a404e5b755e 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlNonElementItem.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlNonElementItem.java @@ -176,15 +176,15 @@ public void removeChildren(String qname) { public abstract OMNode value(); @Override - public IteratorValue getIterator() { - return new IteratorValue() { + public IteratorValue getIterator() { + return new IteratorValue<>() { @Override public boolean hasNext() { return false; } @Override - public Object next() { + public Void next() { throw new NoSuchElementException(); } }; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlPi.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlPi.java index 764b4e88d460..8ece7823964d 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlPi.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlPi.java @@ -34,8 +34,8 @@ */ public class XmlPi extends XmlNonElementItem { - private String data; - private String target; + private final String data; + private final String target; public XmlPi(String data, String target) { this.data = data; @@ -51,9 +51,9 @@ public XmlPi(String data, String target, boolean readonly) { } @Override - public IteratorValue getIterator() { + public IteratorValue getIterator() { XmlPi that = this; - return new IteratorValue() { + return new IteratorValue<>() { boolean read = false; @Override public boolean hasNext() { @@ -61,7 +61,7 @@ public boolean hasNext() { } @Override - public Object next() { + public XmlPi next() { if (!read) { this.read = true; return that; diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlQName.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlQName.java index 6ef15a47244b..d4cc801acc11 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlQName.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlQName.java @@ -162,26 +162,32 @@ public Object frozenCopy(Map refs) { return copy; } + @Override public String getLocalName() { return localName; } + @Override public void setLocalName(String localName) { this.localName = localName; } + @Override public String getUri() { return uri; } + @Override public void setUri(String uri) { this.uri = uri; } + @Override public String getPrefix() { return prefix; } + @Override public void setPrefix(String prefix) { this.prefix = prefix; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlSequence.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlSequence.java index 1fa8c0dffdc7..cca632cf9dd2 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlSequence.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlSequence.java @@ -31,6 +31,7 @@ import io.ballerina.runtime.api.values.BXmlSequence; import io.ballerina.runtime.internal.CycleUtils; import io.ballerina.runtime.internal.IteratorUtils; +import io.ballerina.runtime.internal.XmlFactory; import io.ballerina.runtime.internal.errors.ErrorCodes; import io.ballerina.runtime.internal.errors.ErrorHelper; import io.ballerina.runtime.internal.types.BArrayType; @@ -70,8 +71,12 @@ public XmlSequence() { this.type = PredefinedTypes.TYPE_XML_NEVER; } - public XmlSequence(List children) { - this.children = children; + public XmlSequence(List values) { + if (values.isEmpty()) { + this.children = values; + return; + } + setSequenceMembersConcatenatingAdjacentTextItems(values); } public XmlSequence(BXml child) { @@ -81,6 +86,7 @@ public XmlSequence(BXml child) { } } + @Override public List getChildrenList() { return children; } @@ -213,7 +219,7 @@ public void setAttributes(BMap attributes) { */ @Override public XmlValue elements() { - List elementsSeq = new ArrayList(); + List elementsSeq = new ArrayList<>(); for (BXml child : children) { if (child.getNodeType() == XmlNodeType.ELEMENT) { elementsSeq.add(child); @@ -319,7 +325,7 @@ public void addChildren(BXml xmlItem) { this.type = getSequenceType(tempExprType); return; } - this.type = PredefinedTypes.TYPE_XML;; + this.type = PredefinedTypes.TYPE_XML; } /** @@ -418,6 +424,7 @@ public XmlValue descendants(List qnames) { return new XmlSequence(descendants); } + @Override public XmlValue descendants() { List descendants = new ArrayList<>(); if (children.size() == 1) { @@ -610,9 +617,9 @@ public boolean isFrozen() { } @Override - public IteratorValue getIterator() { - return new IteratorValue() { - Iterator iterator = children.iterator(); + public IteratorValue getIterator() { + return new IteratorValue<>() { + final Iterator iterator = children.iterator(); @Override public boolean hasNext() { @@ -620,12 +627,35 @@ public boolean hasNext() { } @Override - public Object next() { + public BXml next() { return iterator.next(); } }; } + private void setSequenceMembersConcatenatingAdjacentTextItems(List values) { + ArrayList members = new ArrayList<>(); + boolean isPreviousValueText = false; + StringBuilder text = new StringBuilder(); + for (BXml value : values) { + if (value.getNodeType() == XmlNodeType.TEXT) { + isPreviousValueText = true; + text.append(value.getTextValue()); + continue; + } + if (isPreviousValueText) { + members.add(XmlFactory.createXMLText(StringUtils.fromString(text.toString()))); + isPreviousValueText = false; + text.setLength(0); + } + members.add(value); + } + if (!text.isEmpty()) { + members.add(XmlFactory.createXMLText(StringUtils.fromString(text.toString()))); + } + this.children = members; + } + private Type getSequenceType(Type tempExprType) { return switch (tempExprType.getTag()) { case TypeTags.XML_ELEMENT_TAG -> PredefinedTypes.TYPE_XML_ELEMENT_SEQUENCE; @@ -641,8 +671,8 @@ private void initializeIteratorNextReturnType() { childrenType = children.get(0).getType(); } else { Set types = new HashSet<>(); - for (int i = 0; i < children.size(); i++) { - types.add(children.get(i).getType()); + for (BXml child : children) { + types.add(child.getType()); } childrenType = new BUnionType(new ArrayList<>(types)); } @@ -669,9 +699,8 @@ public boolean equals(Object o, Set visitedValues) { if (o instanceof XmlSequence rhsXMLSequence) { return isXMLSequenceChildrenEqual(this.getChildrenList(), rhsXMLSequence.getChildrenList()); } - if (o instanceof XmlItem) { - return this.getChildrenList().size() == 1 && - isEqual(this.getChildrenList().get(0), o); + if (this.isSingleton() && (o instanceof XmlValue)) { + return isEqual(this.getChildrenList().get(0), o); } return this.getChildrenList().isEmpty() && TypeUtils.getType(o) == PredefinedTypes.TYPE_XML_NEVER; } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlText.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlText.java index 396d9807abb0..5103c770ebe3 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlText.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlText.java @@ -35,7 +35,7 @@ */ public class XmlText extends XmlNonElementItem { - private String data; + private final String data; public XmlText(String data) { // data is the content of xml comment or text node @@ -92,9 +92,9 @@ public OMNode value() { } @Override - public IteratorValue getIterator() { + public IteratorValue getIterator() { XmlText that = this; - return new IteratorValue() { + return new IteratorValue<>() { boolean read = false; @Override public boolean hasNext() { @@ -102,7 +102,7 @@ public boolean hasNext() { } @Override - public Object next() { + public XmlText next() { if (!read) { this.read = true; return that; @@ -127,11 +127,11 @@ public boolean equals(Object obj) { */ @Override public boolean equals(Object o, Set visitedValues) { - if (o instanceof XmlText rhsXMLText) { - return this.getTextValue().equals(rhsXMLText.getTextValue()); + if ((o instanceof XmlText) || isXmlSequenceWithSingletonTextValue(o)) { + return this.getTextValue().equals(((XmlValue) o).getTextValue()); } - return this.getType() == PredefinedTypes.TYPE_XML_NEVER && (o instanceof XmlSequence) && - ((XmlSequence) o).getChildrenList().isEmpty(); + return this.getType() == PredefinedTypes.TYPE_XML_NEVER && (o instanceof XmlSequence xmlSequence) && + xmlSequence.getChildrenList().isEmpty(); } @Override @@ -143,4 +143,11 @@ public int hashCode() { public Type getType() { return this.type; } + + private boolean isXmlSequenceWithSingletonTextValue(Object o) { + if (!(o instanceof XmlSequence sequence)) { + return false; + } + return sequence.isSingleton() && sequence.getItem(0).getNodeType() == XmlNodeType.TEXT; + } } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlValue.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlValue.java index c2999bd4330f..23443629ca47 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlValue.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/internal/values/XmlValue.java @@ -60,6 +60,7 @@ public abstract class XmlValue implements RefValue, BXml, CollectionValue { protected Type iteratorNextReturnType; + @Override public abstract int size(); /** @@ -68,6 +69,7 @@ public abstract class XmlValue implements RefValue, BXml, CollectionValue { * @param attributeName Qualified name of the attribute * @return Value of the attribute */ + @Override public BString getAttribute(BXmlQName attributeName) { return getAttribute(attributeName.getLocalName(), attributeName.getUri(), attributeName.getPrefix()); } @@ -79,6 +81,7 @@ public BString getAttribute(BXmlQName attributeName) { * @param attributeName Qualified name of the attribute * @param value Value of the attribute */ + @Override @Deprecated public void setAttribute(BXmlQName attributeName, String value) { setAttributeOnInitialization(attributeName.getLocalName(), attributeName.getUri(), attributeName.getPrefix(), @@ -103,6 +106,7 @@ public void setAttribute(BXmlQName attributeName, BString value) { * * @return Attributes as a {@link MapValueImpl} */ + @Override public abstract MapValue getAttributesMap(); /** @@ -110,6 +114,7 @@ public void setAttribute(BXmlQName attributeName, BString value) { * * @param attributes Attributes to be set. */ + @Override public abstract void setAttributes(BMap attributes); /** @@ -117,11 +122,13 @@ public void setAttribute(BXmlQName attributeName, BString value) { * * @return Type of the XML */ + @Override public abstract XmlNodeType getNodeType(); /** * Builds itself. */ + @Override public abstract void build(); @Override @@ -213,8 +220,10 @@ public void setChildren(XmlValue seq) { setChildren((BXml) seq); } + @Override public abstract XmlValue children(); + @Override public abstract XmlValue children(String qname); /** @@ -229,13 +238,14 @@ public Object frozenCopy(Map refs) { return copy; } + @Override public abstract XmlValue getItem(int index); @Override public void serialize(OutputStream outputStream) { try { - if (outputStream instanceof BallerinaXmlSerializer) { - ((BallerinaXmlSerializer) outputStream).write(this); + if (outputStream instanceof BallerinaXmlSerializer xmlSerializer) { + xmlSerializer.write(this); } else { BallerinaXmlSerializer xmlSerializer = new BallerinaXmlSerializer(outputStream); xmlSerializer.write(this); diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/ObservabilityConstants.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/ObservabilityConstants.java index ccda1782adff..c519b3185f66 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/ObservabilityConstants.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/ObservabilityConstants.java @@ -24,7 +24,7 @@ * Open Tracing Specification. *

*/ -public class ObservabilityConstants { +public final class ObservabilityConstants { private ObservabilityConstants() { } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/ObserveUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/ObserveUtils.java index dcc52ccd6b5a..759bf3f0210b 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/ObserveUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/ObserveUtils.java @@ -63,7 +63,8 @@ * * @since 0.985.0 */ -public class ObserveUtils { +public final class ObserveUtils { + private static final List observers = new CopyOnWriteArrayList<>(); private static final boolean enabled; private static final boolean metricsEnabled; @@ -96,6 +97,9 @@ public class ObserveUtils { enabled = metricsEnabled || tracingEnabled; } + private ObserveUtils() { + } + private static T readConfig(VariableKey specificKey, VariableKey inheritedKey, T defaultValue) { T value; if (ConfigMap.containsKey(specificKey)) { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/BallerinaMetricsObserver.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/BallerinaMetricsObserver.java index 8b13a742095e..d796ed991094 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/BallerinaMetricsObserver.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/BallerinaMetricsObserver.java @@ -127,6 +127,10 @@ private void stopObservation(ObserverContext observerContext) { "Total response response time for all requests", tags)).increment(duration); metricRegistry.counter(new MetricId("requests_total", "Total number of requests", tags)).increment(); + if (statusCode != null && 400 <= statusCode && statusCode < 600) { + metricRegistry.counter(new MetricId("response_errors_total", + "Total number of response errors", tags)).increment(); + } } catch (RuntimeException e) { handleError("multiple metrics", tags, e); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/Counter.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/Counter.java index 3957b4d53aa9..6618908345d2 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/Counter.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/Counter.java @@ -80,6 +80,7 @@ public Builder tags(Map tags) { return this; } + @Override public Counter build() { return DefaultMetricRegistry.getInstance().getMetricProvider(). newCounter(new MetricId(name, description, tags)); @@ -99,6 +100,7 @@ public Counter register(MetricRegistry registry) { /** * Register the Metric to the registry. */ + @Override default Counter register() { return DefaultMetricRegistry.getInstance().register(this); } @@ -106,6 +108,7 @@ default Counter register() { /** * Unregisters the metric to the registry. */ + @Override default void unregister() { DefaultMetricRegistry.getInstance().unregister(this); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/DefaultMetricRegistry.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/DefaultMetricRegistry.java index 4004e6888571..f088a929ba8d 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/DefaultMetricRegistry.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/DefaultMetricRegistry.java @@ -24,10 +24,13 @@ /** * Hold a default {@link MetricRegistry} instance, which is used by Metric APIs. */ -public class DefaultMetricRegistry { +public final class DefaultMetricRegistry { private static MetricRegistry instance = new MetricRegistry(new NoOpMetricProvider()); + private DefaultMetricRegistry() { + } + /** * Get the default {@link MetricRegistry}. * diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/Gauge.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/Gauge.java index 915a1efc6973..fc000bd32288 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/Gauge.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/Gauge.java @@ -119,6 +119,7 @@ public Gauge build() { * * @return The registered Gauge instance. */ + @Override default Gauge register() { return DefaultMetricRegistry.getInstance().register(this); } @@ -128,6 +129,7 @@ default Gauge register() { * Unregisters the metric to the registry. * */ + @Override default void unregister() { DefaultMetricRegistry.getInstance().unregister(this); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/MetricConstants.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/MetricConstants.java index c2f16d24da44..e6e29a1272df 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/MetricConstants.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/MetricConstants.java @@ -21,7 +21,7 @@ * Defines the types of the metrics supported. * @since 0.980.0 */ -public class MetricConstants { +public final class MetricConstants { private MetricConstants() {} diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/MetricRegistry.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/MetricRegistry.java index feb5ec8dc814..04a5ef722aab 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/MetricRegistry.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/MetricRegistry.java @@ -24,7 +24,6 @@ import java.util.concurrent.ConcurrentMap; import java.util.function.Supplier; import java.util.function.ToDoubleFunction; -import java.util.stream.Collectors; /** * Registry for keeping metrics by name. @@ -191,7 +190,7 @@ private void unregister(Metric registerMetric, Class metri */ public void remove(String name) { List ids = metrics.keySet().stream() - .filter(id -> id.getName().equals(name)).collect(Collectors.toList()); + .filter(id -> id.getName().equals(name)).toList(); ids.forEach(metrics::remove); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/PolledGauge.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/PolledGauge.java index 8e49ca6d21b7..4227b357ae36 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/PolledGauge.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/PolledGauge.java @@ -51,8 +51,8 @@ class Builder implements Metric.Builder, PolledGauge> { // Expecting at least 10 tags private final Set tags = new HashSet<>(10); private String description; - private T obj; - private ToDoubleFunction valueFunction; + private final T obj; + private final ToDoubleFunction valueFunction; private Builder(String name, T obj, ToDoubleFunction valueFunction) { this.name = name; @@ -67,25 +67,25 @@ public Builder description(String description) { } @Override - public Builder tags(String... keyValues) { + public Builder tags(String... keyValues) { Tags.tags(this.tags, keyValues); return this; } @Override - public Builder tags(Iterable tags) { + public Builder tags(Iterable tags) { Tags.tags(this.tags, tags); return this; } @Override - public Builder tag(String key, String value) { + public Builder tag(String key, String value) { Tags.tags(this.tags, key, value); return this; } @Override - public Builder tags(Map tags) { + public Builder tags(Map tags) { Tags.tags(this.tags, tags); return this; } @@ -112,6 +112,7 @@ public PolledGauge build() { * * @return The registered gauge instance. */ + @Override default PolledGauge register() { return DefaultMetricRegistry.getInstance().register(this); } @@ -120,6 +121,7 @@ default PolledGauge register() { * Default implementation for register polled gauge. * */ + @Override default void unregister() { DefaultMetricRegistry.getInstance().unregister(this); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/StatisticConfig.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/StatisticConfig.java index 06510349ef51..8d311ca39de9 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/StatisticConfig.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/StatisticConfig.java @@ -103,7 +103,7 @@ public static Builder builder() { */ public static class Builder { - private StatisticConfig config = new StatisticConfig(); + private final StatisticConfig config = new StatisticConfig(); /** * Percentiles to compute and publish. Percentile is in the domain [0,1]. diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/Tags.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/Tags.java index 03468bdc3255..8314ecbecd5a 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/Tags.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/metrics/Tags.java @@ -23,7 +23,7 @@ /** * Utility methods to add tags to an existing list of {@link Tag Tags}. */ -public class Tags { +public final class Tags { private Tags() { } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/tracer/BSpan.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/tracer/BSpan.java index ee660c46f317..8350ce227bb4 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/tracer/BSpan.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/tracer/BSpan.java @@ -53,8 +53,8 @@ public class BSpan { private static final MapType IMMUTABLE_STRING_MAP_TYPE = TypeCreator.createMapType( PredefinedTypes.TYPE_STRING, true); - private static PropagatingParentContextGetter getter = new PropagatingParentContextGetter(); - private static PropagatingParentContextSetter setter = new PropagatingParentContextSetter(); + private static final PropagatingParentContextGetter GETTER = new PropagatingParentContextGetter(); + private static final PropagatingParentContextSetter SETTER = new PropagatingParentContextSetter(); static class PropagatingParentContextGetter implements TextMapGetter> { @Override @@ -137,7 +137,7 @@ public static BSpan start(Map parentTraceContext, String service Tracer tracer = TracersStore.getInstance().getTracer(serviceName); Context parentContext = TracersStore.getInstance().getPropagators() - .getTextMapPropagator().extract(Context.current(), parentTraceContext, getter); + .getTextMapPropagator().extract(Context.current(), parentTraceContext, GETTER); return start(tracer, parentContext, operationName, isClient); } @@ -165,7 +165,7 @@ public Map extractContextAsHttpHeaders() { if (span != null) { carrierMap = new HashMap<>(); TextMapPropagator propagator = TracersStore.getInstance().getPropagators().getTextMapPropagator(); - propagator.inject(Context.current().with(span), carrierMap, setter); + propagator.inject(Context.current().with(span), carrierMap, SETTER); } else { carrierMap = Collections.emptyMap(); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/tracer/TraceConstants.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/tracer/TraceConstants.java index c3d811e3ff4f..1b74c86b47e8 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/tracer/TraceConstants.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/tracer/TraceConstants.java @@ -25,7 +25,7 @@ * * @since 0.964.1 */ -public class TraceConstants { +public final class TraceConstants { private TraceConstants() { } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/tracer/TracingUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/tracer/TracingUtils.java index 819c8e171902..1747c16ac9b4 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/tracer/TracingUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/observability/tracer/TracingUtils.java @@ -34,7 +34,7 @@ /** * Util class to hold tracing specific util methods. */ -public class TracingUtils { +public final class TracingUtils { private TracingUtils() { } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/TransactionConstants.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/TransactionConstants.java index dd000d6dfa8e..63797eee1283 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/TransactionConstants.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/TransactionConstants.java @@ -31,7 +31,8 @@ * * @since 1.0 */ -public class TransactionConstants { +public final class TransactionConstants { + //Co-ordinator functions public static final String COORDINATOR_ABORT_TRANSACTION = "abortTransaction"; @@ -75,4 +76,9 @@ public class TransactionConstants { public static final int NO_CHECKPOINT_INTERVAL = -1; public static final int IN_MEMORY_CHECKPOINT_INTERVAL = 25; public static final String ERROR_MESSAGE_PREFIX = "error:"; + public static final int DEFAULT_TRX_AUTO_COMMIT_TIMEOUT = 120; + public static final int DEFAULT_TRX_CLEANUP_TIMEOUT = 600; + + private TransactionConstants() { + } } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/TransactionLocalContext.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/TransactionLocalContext.java index 7f8cdcdea9d9..bcebf965ab05 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/TransactionLocalContext.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/TransactionLocalContext.java @@ -22,9 +22,10 @@ import io.ballerina.runtime.internal.scheduling.Strand; import java.nio.ByteBuffer; +import java.util.ArrayDeque; +import java.util.Deque; import java.util.HashMap; import java.util.Map; -import java.util.Stack; /** * {@code TransactionLocalContext} stores the transaction related information. @@ -33,22 +34,22 @@ */ public class TransactionLocalContext { - private String globalTransactionId; - private String url; - private String protocol; + private final String globalTransactionId; + private final String url; + private final String protocol; private int transactionLevel; - private Map allowedTransactionRetryCounts; - private Map currentTransactionRetryCounts; + private final Map allowedTransactionRetryCounts; + private final Map currentTransactionRetryCounts; private Map transactionContextStore; - private Stack transactionBlockIdStack; - private Stack transactionFailure; - private static final TransactionResourceManager transactionResourceManager = + private final Deque transactionBlockIdStack; + private final Deque transactionFailure; + private static final TransactionResourceManager TRANSACTION_RESOURCE_MANAGER = TransactionResourceManager.getInstance(); private boolean isResourceParticipant; private Object rollbackOnlyError; private Object transactionData; - private BArray transactionId; + private final BArray transactionId; private boolean isTransactional; private TransactionLocalContext(String globalTransactionId, String url, String protocol, Object infoRecord) { @@ -59,8 +60,8 @@ private TransactionLocalContext(String globalTransactionId, String url, String p this.allowedTransactionRetryCounts = new HashMap<>(); this.currentTransactionRetryCounts = new HashMap<>(); this.transactionContextStore = new HashMap<>(); - this.transactionBlockIdStack = new Stack<>(); - this.transactionFailure = new Stack<>(); + this.transactionBlockIdStack = new ArrayDeque<>(); + this.transactionFailure = new ArrayDeque<>(); this.rollbackOnlyError = null; this.isTransactional = true; this.transactionId = ValueCreator.createArrayValue(globalTransactionId.getBytes()); @@ -71,7 +72,7 @@ private void validateAndPutTransactionInfo(ByteBuffer transactionIdBytes, Object if (infoRecord == null) { return; } - transactionResourceManager.transactionInfoMap.put(transactionIdBytes, infoRecord); + TRANSACTION_RESOURCE_MANAGER.transactionInfoMap.put(transactionIdBytes, infoRecord); } public static TransactionLocalContext createTransactionParticipantLocalCtx(String globalTransactionId, @@ -104,7 +105,7 @@ public void addCurrentTransactionBlockId(String blockId) { } public boolean hasTransactionBlock() { - return !transactionBlockIdStack.empty(); + return !transactionBlockIdStack.isEmpty(); } public String getURL() { @@ -159,7 +160,8 @@ public boolean isRetryPossible(Strand context, String transactionId) { public void notifyAbortAndClearTransaction(String transactionBlockId) { transactionContextStore.clear(); - transactionResourceManager.notifyAbort(globalTransactionId, transactionBlockId); + TRANSACTION_RESOURCE_MANAGER.endXATransaction(globalTransactionId, transactionBlockId, true); + TRANSACTION_RESOURCE_MANAGER.notifyAbort(globalTransactionId, transactionBlockId); } public void setRollbackOnlyError(Object error) { @@ -179,12 +181,12 @@ public Object getTransactionData() { } public void removeTransactionInfo() { - transactionResourceManager.transactionInfoMap.remove(ByteBuffer.wrap(transactionId.getBytes())); + TRANSACTION_RESOURCE_MANAGER.transactionInfoMap.remove(ByteBuffer.wrap(transactionId.getBytes())); } public void notifyLocalParticipantFailure() { String blockId = transactionBlockIdStack.peek(); - transactionResourceManager.notifyLocalParticipantFailure(globalTransactionId, blockId); + TRANSACTION_RESOURCE_MANAGER.notifyLocalParticipantFailure(globalTransactionId, blockId); } public void notifyLocalRemoteParticipantFailure() { @@ -210,7 +212,7 @@ public void markFailure() { } public TransactionFailure getAndClearFailure() { - if (transactionFailure.empty()) { + if (transactionFailure.isEmpty()) { return null; } TransactionFailure failure = transactionFailure.pop(); @@ -219,7 +221,7 @@ public TransactionFailure getAndClearFailure() { } public TransactionFailure getFailure() { - if (transactionFailure.empty()) { + if (transactionFailure.isEmpty()) { return null; } return transactionFailure.peek(); @@ -234,7 +236,7 @@ public void setResourceParticipant(boolean resourceParticipant) { } public Object getInfoRecord() { - return transactionResourceManager.getTransactionRecord(transactionId); + return TRANSACTION_RESOURCE_MANAGER.getTransactionRecord(transactionId); } public boolean isTransactional() { diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/TransactionResourceManager.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/TransactionResourceManager.java index 1bf22e7d2502..cc383b5af75d 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/TransactionResourceManager.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/TransactionResourceManager.java @@ -41,13 +41,14 @@ import java.nio.ByteBuffer; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentSkipListSet; import javax.transaction.HeuristicMixedException; @@ -61,12 +62,15 @@ import javax.transaction.xa.Xid; import static io.ballerina.runtime.api.constants.RuntimeConstants.BALLERINA_BUILTIN_PKG_PREFIX; +import static io.ballerina.runtime.transactions.TransactionConstants.DEFAULT_TRX_AUTO_COMMIT_TIMEOUT; +import static io.ballerina.runtime.transactions.TransactionConstants.DEFAULT_TRX_CLEANUP_TIMEOUT; import static io.ballerina.runtime.transactions.TransactionConstants.DEFAULT_CHECKPOINT_INTERVAL; import static io.ballerina.runtime.transactions.TransactionConstants.ERROR_MESSAGE_PREFIX; import static io.ballerina.runtime.transactions.TransactionConstants.NO_CHECKPOINT_INTERVAL; import static io.ballerina.runtime.transactions.TransactionConstants.TRANSACTION_PACKAGE_ID; import static io.ballerina.runtime.transactions.TransactionConstants.TRANSACTION_PACKAGE_NAME; import static io.ballerina.runtime.transactions.TransactionConstants.TRANSACTION_PACKAGE_VERSION; +import static javax.transaction.xa.XAResource.TMFAIL; import static javax.transaction.xa.XAResource.TMNOFLAGS; import static javax.transaction.xa.XAResource.TMSUCCESS; @@ -89,34 +93,32 @@ public class TransactionResourceManager { private static final String ATOMIKOS_LOG_BASE_PROPERTY = "com.atomikos.icatch.log_base_dir"; private static final String ATOMIKOS_LOG_NAME_PROPERTY = "com.atomikos.icatch.log_base_name"; private static final String ATOMIKOS_REGISTERED_PROPERTY = "com.atomikos.icatch.registered"; + public static final String TRANSACTION_AUTO_COMMIT_TIMEOUT_KEY = "transactionAutoCommitTimeout"; + public static final String TRANSACTION_CLEANUP_TIMEOUT_KEY = "transactionCleanupTimeout"; - private static final Logger log = LoggerFactory.getLogger(TransactionResourceManager.class); - private Map> resourceRegistry; + private static final Logger LOG = LoggerFactory.getLogger(TransactionResourceManager.class); + private final Map> resourceRegistry = new HashMap<>(); private Map trxRegistry; private Map xidRegistry; - private Map> committedFuncRegistry; - private Map> abortedFuncRegistry; + private final Map>> committedFuncRegistry = new HashMap<>(); + private final Map>> abortedFuncRegistry = new HashMap<>(); - private ConcurrentSkipListSet failedResourceParticipantSet = new ConcurrentSkipListSet<>(); - private ConcurrentSkipListSet failedLocalParticipantSet = new ConcurrentSkipListSet<>(); - private ConcurrentHashMap> localParticipants = new ConcurrentHashMap<>(); + private final Set failedResourceParticipantSet = new ConcurrentSkipListSet<>(); + private final Set failedLocalParticipantSet = new ConcurrentSkipListSet<>(); + private final ConcurrentMap> localParticipants = new ConcurrentHashMap<>(); - private boolean transactionManagerEnabled; - private static final PrintStream stderr = System.err; + private final boolean transactionManagerEnabled; + private static final PrintStream STDERR = System.err; + final Map transactionInfoMap = new ConcurrentHashMap<>(); private LogManager logManager; private RecoveryManager recoveryManager; private boolean startupRecoverySuccessful = false; RuntimeDiagnosticLog diagnosticLog = new RuntimeDiagnosticLog(); - Map transactionInfoMap; private TransactionResourceManager() { - resourceRegistry = new HashMap<>(); - committedFuncRegistry = new HashMap<>(); - abortedFuncRegistry = new HashMap<>(); - transactionInfoMap = new ConcurrentHashMap<>(); transactionManagerEnabled = getTransactionManagerEnabled(); if (transactionManagerEnabled) { trxRegistry = new HashMap<>(); @@ -160,14 +162,14 @@ public Map> getResourceRegistry() { * This method sets values for atomikos transaction log path and name properties using the available configs. */ private void setLogProperties() { - final Path projectRoot = Paths.get(RuntimeUtils.USER_DIR); + final Path projectRoot = Path.of(RuntimeUtils.USER_DIR); if (projectRoot != null) { String logDir = getTransactionLogDirectory(); - Path logDirPath = Paths.get(logDir); + Path logDirPath = Path.of(logDir); Path transactionLogDirectory; if (!logDirPath.isAbsolute()) { logDir = projectRoot.toAbsolutePath().toString() + File.separatorChar + logDir; - transactionLogDirectory = Paths.get(logDir); + transactionLogDirectory = Path.of(logDir); } else { transactionLogDirectory = logDirPath; } @@ -175,7 +177,7 @@ private void setLogProperties() { try { Files.createDirectory(transactionLogDirectory); } catch (IOException e) { - stderr.println(ERROR_MESSAGE_PREFIX + " failed to create transaction log directory in " + logDir); + STDERR.println(ERROR_MESSAGE_PREFIX + " failed to create transaction log directory in " + logDir); } } System.setProperty(ATOMIKOS_LOG_BASE_PROPERTY, logDir); @@ -213,6 +215,56 @@ private String getTransactionLogDirectory() { } } + /** + * This method gets the user specified config for the transaction auto commit timeout. Default is 120. + * + * @return int transaction auto commit timeout value + */ + public static int getTransactionAutoCommitTimeout() { + VariableKey transactionAutoCommitTimeoutKey = new VariableKey(TRANSACTION_PACKAGE_ID, + TRANSACTION_AUTO_COMMIT_TIMEOUT_KEY, PredefinedTypes.TYPE_INT, false); + if (!ConfigMap.containsKey(transactionAutoCommitTimeoutKey)) { + return DEFAULT_TRX_AUTO_COMMIT_TIMEOUT; + } else { + Object configValue = ConfigMap.get(transactionAutoCommitTimeoutKey); + if (configValue == null) { + return DEFAULT_TRX_AUTO_COMMIT_TIMEOUT; + } + return parseTimeoutValue(configValue, DEFAULT_TRX_AUTO_COMMIT_TIMEOUT); + } + } + + /** + * This method gets the user specified config for cleaning up dead transactions. Default is 600. + * + * @return int transaction cleanup after value + */ + public static int getTransactionCleanupTimeout() { + VariableKey transactionCleanupTimeoutKey = new VariableKey(TRANSACTION_PACKAGE_ID, + TRANSACTION_CLEANUP_TIMEOUT_KEY, + PredefinedTypes.TYPE_INT, false); + if (!ConfigMap.containsKey(transactionCleanupTimeoutKey)) { + return DEFAULT_TRX_CLEANUP_TIMEOUT; + } else { + Object configValue = ConfigMap.get(transactionCleanupTimeoutKey); + if (configValue == null) { + return DEFAULT_TRX_CLEANUP_TIMEOUT; + } + return parseTimeoutValue(configValue, DEFAULT_TRX_CLEANUP_TIMEOUT); + } + } + + private static int parseTimeoutValue(Object configValue, int defaultValue) { + if (!(configValue instanceof Number number)) { + return defaultValue; + } + int timeoutValue = number.intValue(); + if (timeoutValue <= 0) { + return defaultValue; + } + return timeoutValue; + } + /** * This method gets the user specified config for ballerina recovery log name. * @@ -233,17 +285,17 @@ private String getRecoveryLogBaseName() { * @return string recovery log directory */ private Path getRecoveryLogDir() { - final Path projectRoot = Paths.get(RuntimeUtils.USER_DIR); + final Path projectRoot = Path.of(RuntimeUtils.USER_DIR); VariableKey recoveryLogDirKey = new VariableKey(TRANSACTION_PACKAGE_ID, "recoveryLogDir", PredefinedTypes.TYPE_STRING, false); if (!ConfigMap.containsKey(recoveryLogDirKey)) { return projectRoot; } String logDir = ((BString) ConfigMap.get(recoveryLogDirKey)).getValue(); - Path logDirPath = Paths.get(logDir); + Path logDirPath = Path.of(logDir); if (!logDirPath.isAbsolute()) { logDir = projectRoot.toAbsolutePath().toString() + File.separatorChar + logDir; - return Paths.get(logDir); + return Path.of(logDir); } return logDirPath; } @@ -311,7 +363,7 @@ public void register(String transactionId, String transactionBlockId, BallerinaT * @param transactionBlockId the block id of the transaction * @param fpValue the function pointer for the committed function */ - public void registerCommittedFunction(String transactionBlockId, BFunctionPointer fpValue) { + public void registerCommittedFunction(String transactionBlockId, BFunctionPointer fpValue) { if (fpValue != null) { committedFuncRegistry.computeIfAbsent(transactionBlockId, list -> new ArrayList<>()).add(fpValue); } @@ -323,7 +375,7 @@ public void registerCommittedFunction(String transactionBlockId, BFunctionPointe * @param transactionBlockId the block id of the transaction * @param fpValue the function pointer for the aborted function */ - public void registerAbortedFunction(String transactionBlockId, BFunctionPointer fpValue) { + public void registerAbortedFunction(String transactionBlockId, BFunctionPointer fpValue) { if (fpValue != null) { abortedFuncRegistry.computeIfAbsent(transactionBlockId, list -> new ArrayList<>()).add(fpValue); } @@ -352,7 +404,7 @@ public void registerParticipation(String gTransactionId, String transactionBlock */ //TODO:Comment for now, might need it for distributed transactions. public boolean prepare(String transactionId, String transactionBlockId) { - endXATransaction(transactionId, transactionBlockId); + endXATransaction(transactionId, transactionBlockId, false); if (transactionManagerEnabled) { return true; } @@ -367,7 +419,7 @@ public boolean prepare(String transactionId, String transactionBlockId) { xaResource.prepare(xid); } } catch (XAException e) { - log.error("error at transaction prepare phase in transaction " + transactionId + LOG.error("error at transaction prepare phase in transaction " + transactionId + ":" + e.getMessage(), e); return false; } @@ -379,7 +431,7 @@ public boolean prepare(String transactionId, String transactionBlockId) { // resource participant reported failure. status = false; } - log.info(String.format("Transaction prepare (participants): %s", status ? "success" : "failed")); + LOG.info(String.format("Transaction prepare (participants): %s", status ? "success" : "failed")); return status; } @@ -403,7 +455,7 @@ public boolean notifyCommit(String transactionId, String transactionBlockId) { } } catch (SystemException | HeuristicMixedException | HeuristicRollbackException | RollbackException e) { - log.error("error when committing transaction " + transactionId + ":" + e.getMessage(), e); + LOG.error("error when committing transaction " + transactionId + ":" + e.getMessage(), e); commitSuccess = false; } } @@ -422,7 +474,7 @@ public boolean notifyCommit(String transactionId, String transactionBlockId) { } } } catch (XAException e) { - log.error("error when committing transaction " + transactionId + ":" + e.getMessage(), e); + LOG.error("error when committing transaction " + transactionId + ":" + e.getMessage(), e); commitSuccess = false; } finally { ctx.close(); @@ -460,7 +512,7 @@ public boolean notifyAbort(String transactionId, String transactionBlockId) { trx.rollback(); } } catch (SystemException e) { - log.error("error when aborting transaction " + transactionId + ":" + e.getMessage(), e); + LOG.error("error when aborting transaction " + transactionId + ":" + e.getMessage(), e); abortSuccess = false; } } @@ -479,7 +531,7 @@ public boolean notifyAbort(String transactionId, String transactionBlockId) { } } } catch (XAException e) { - log.error("error when aborting the transaction " + transactionId + ":" + e.getMessage(), e); + LOG.error("error when aborting the transaction " + transactionId + ":" + e.getMessage(), e); abortSuccess = false; } finally { ctx.close(); @@ -518,7 +570,7 @@ public void beginXATransaction(String transactionId, String transactionBlockId, trxRegistry.put(combinedId, trx); } } catch (SystemException | NotSupportedException e) { - log.error("error in initiating transaction " + transactionId + ":" + e.getMessage(), e); + LOG.error("error in initiating transaction " + transactionId + ":" + e.getMessage(), e); } } else { Xid xid = xidRegistry.get(combinedId); @@ -529,7 +581,7 @@ public void beginXATransaction(String transactionId, String transactionBlockId, try { xaResource.start(xid, TMNOFLAGS); } catch (XAException e) { - log.error("error in starting XA transaction " + transactionId + ":" + e.getMessage(), e); + LOG.error("error in starting XA transaction " + transactionId + ":" + e.getMessage(), e); } } } @@ -591,7 +643,7 @@ public void notifyTransactionAbort(String transactionBlockId) { * @return Array of rollback handlers */ public BArray getRegisteredRollbackHandlerList() { - List abortFunctions = + List> abortFunctions = abortedFuncRegistry.get(Scheduler.getStrand().currentTrxContext.getGlobalTransactionId()); if (abortFunctions != null && !abortFunctions.isEmpty()) { Collections.reverse(abortFunctions); @@ -608,7 +660,7 @@ public BArray getRegisteredRollbackHandlerList() { * @return Array of commit handlers */ public BArray getRegisteredCommitHandlerList() { - List commitFunctions = + List> commitFunctions = committedFuncRegistry.get(Scheduler.getStrand().currentTrxContext.getGlobalTransactionId()); if (commitFunctions != null && !commitFunctions.isEmpty()) { Collections.reverse(commitFunctions); @@ -658,7 +710,7 @@ public TransactionLocalContext getCurrentTransactionContext() { * @param transactionId the global transaction id * @param transactionBlockId the block id of the transaction */ - void endXATransaction(String transactionId, String transactionBlockId) { + void endXATransaction(String transactionId, String transactionBlockId, boolean abortOnly) { String combinedId = generateCombinedTransactionId(transactionId, transactionBlockId); if (transactionManagerEnabled) { Transaction trx = trxRegistry.get(combinedId); @@ -672,7 +724,7 @@ void endXATransaction(String transactionId, String transactionBlockId) { trx.delistResource(xaResource, TMSUCCESS); } } catch (IllegalStateException | SystemException e) { - log.error("error in ending the XA transaction " + transactionId + LOG.error("error in ending the XA transaction " + transactionId + ":" + e.getMessage(), e); } } @@ -686,10 +738,10 @@ void endXATransaction(String transactionId, String transactionBlockId) { try { XAResource xaResource = ctx.getXAResource(); if (xaResource != null) { - ctx.getXAResource().end(xid, TMSUCCESS); + xaResource.end(xid, abortOnly ? TMFAIL : TMSUCCESS); } } catch (XAException e) { - log.error("error in ending XA transaction " + transactionId + ":" + e.getMessage(), e); + LOG.error("error in ending XA transaction " + transactionId + ":" + e.getMessage(), e); } } } @@ -716,11 +768,11 @@ private String generateCombinedTransactionId(String transactionId, String transa public void notifyResourceFailure(String gTransactionId) { failedResourceParticipantSet.add(gTransactionId); // The resource excepted (uncaught). - log.info("Trx infected callable unit excepted id : " + gTransactionId); + LOG.info("Trx infected callable unit excepted id : " + gTransactionId); } public void notifyLocalParticipantFailure(String gTransactionId, String blockId) { - ConcurrentSkipListSet participantBlockIds = localParticipants.get(gTransactionId); + Set participantBlockIds = localParticipants.get(gTransactionId); if (participantBlockIds != null && participantBlockIds.contains(blockId)) { failedLocalParticipantSet.add(gTransactionId); } diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/TransactionUtils.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/TransactionUtils.java index 37d17656df56..33b0f88edcdc 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/TransactionUtils.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/TransactionUtils.java @@ -47,12 +47,15 @@ * * @since 1.0 */ -public class TransactionUtils { +public final class TransactionUtils { private static final StrandMetadata TRX_METADATA = new StrandMetadata(BALLERINA_BUILTIN_PKG_PREFIX, TRANSACTION_PACKAGE_NAME, TRANSACTION_PACKAGE_VERSION, "onAbort"); + private TransactionUtils() { + } + public static void notifyTransactionAbort(Strand strand, String globalTransactionId, String transactionBlockId) { executeFunction(strand.scheduler, TransactionUtils.class.getClassLoader(), TRANSACTION_PACKAGE_FQN, TRANSACTION_BLOCK_CLASS_NAME, COORDINATOR_ABORT_TRANSACTION, globalTransactionId, diff --git a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/XIDGenerator.java b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/XIDGenerator.java index 61366890d567..2eda372c3a1f 100644 --- a/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/XIDGenerator.java +++ b/bvm/ballerina-runtime/src/main/java/io/ballerina/runtime/transactions/XIDGenerator.java @@ -23,7 +23,7 @@ * * @since 1.0 */ -public class XIDGenerator { +public final class XIDGenerator { // DEFAULT_FORMAT will be unique for ballerina but same for each transaction private static final int DEFAULT_FORMAT = ('B' << 24) + ('A' << 16) + ('L' << 8); diff --git a/bvm/ballerina-runtime/src/main/java/module-info.java b/bvm/ballerina-runtime/src/main/java/module-info.java index 857d248a3977..32a43bd94043 100644 --- a/bvm/ballerina-runtime/src/main/java/module-info.java +++ b/bvm/ballerina-runtime/src/main/java/module-info.java @@ -1,4 +1,5 @@ module io.ballerina.runtime { + uses io.ballerina.runtime.api.launch.LaunchListener; requires java.xml; requires org.apache.commons.text; requires axiom.api; @@ -15,7 +16,6 @@ requires transactions.jta; requires java.transaction; requires java.naming; - requires org.apache.commons.lang3; requires io.ballerina.identifier; requires jdk.unsupported; @@ -45,28 +45,27 @@ io.ballerina.lang.floatingpoint, io.ballerina.lang.internal, io.ballerina.lang.function, io.ballerina.lang.regexp, io.ballerina.runtime.profiler; exports io.ballerina.runtime.internal.commons to io.ballerina.lang.value; - exports io.ballerina.runtime.internal.launch to io.ballerina.testerina.runtime, io.ballerina.packerina, - ballerina.test.listener, io.ballerina.cli, org.ballerinalang.debugadapter.runtime; - exports io.ballerina.runtime.internal.scheduling to io.ballerina.cli.utils, io.ballerina.java, + exports io.ballerina.runtime.internal.launch to io.ballerina.testerina.runtime, ballerina.test.listener, + io.ballerina.cli, org.ballerinalang.debugadapter.runtime; + exports io.ballerina.runtime.internal.scheduling to io.ballerina.java, io.ballerina.lang.array, io.ballerina.lang.error, io.ballerina.lang.internal, io.ballerina.lang.map, io.ballerina.lang.table, io.ballerina.lang.transaction, io.ballerina.lang.value, io.ballerina.lang.xml, - io.ballerina.log.api, io.ballerina.testerina.core, io.ballerina.testerina.runtime, io.ballerina.shell, + io.ballerina.testerina.core, io.ballerina.testerina.runtime, io.ballerina.shell, org.ballerinalang.debugadapter.runtime, io.ballerina.lang.function, io.ballerina.runtime.profiler; exports io.ballerina.runtime.internal.util to io.ballerina.testerina.runtime, io.ballerina.lang, io.ballerina.lang.integer, io.ballerina.lang.floatingpoint, io.ballerina.lang.array, io.ballerina.lang.table, io.ballerina.java, io.ballerina.lang.map, io.ballerina.lang.string, io.ballerina.lang.xml, io.ballerina.lang.bool, io.ballerina.lang.error, io.ballerina.lang.internal, - io.ballerina.lang.value, io.ballerina.auth, io.ballerina.runtime.api, io.ballerina.cli.utils, - io.ballerina.cli; + io.ballerina.lang.value, io.ballerina.cli; exports io.ballerina.runtime.internal.errors to io.ballerina.lang.value, io.ballerina.lang.integer, io.ballerina.java, io.ballerina.lang.internal, io.ballerina.lang.array, io.ballerina.lang.bool, io.ballerina.lang.floatingpoint, io.ballerina.lang.map, io.ballerina.lang.string, io.ballerina.lang.table, - io.ballerina.lang.xml, io.ballerina.testerina.core, io.ballerina.cli.utils, io.ballerina.cli, + io.ballerina.lang.xml, io.ballerina.testerina.core, io.ballerina.cli, io.ballerina.lang.decimal, org.ballerinalang.debugadapter.runtime, io.ballerina.lang.function, io.ballerina.lang.regexp; exports io.ballerina.runtime.internal.values to io.ballerina.testerina.core, io.ballerina.testerina.runtime, io.ballerina.lang.xml, org.ballerinalang.debugadapter.runtime, io.ballerina.lang.query, - io.ballerina.lang.function, io.ballerina.lang.regexp, io.ballerina.lang.value; + io.ballerina.lang.function, io.ballerina.lang.regexp, io.ballerina.lang.value, io.ballerina.lang.internal, io.ballerina.lang.array; exports io.ballerina.runtime.internal.configurable to io.ballerina.lang.internal; exports io.ballerina.runtime.internal.types to io.ballerina.lang.typedesc, io.ballerina.testerina.runtime, org.ballerinalang.debugadapter.runtime, io.ballerina.lang.function, io.ballerina.lang.regexp, io.ballerina.testerina.core; diff --git a/bvm/ballerina-runtime/src/main/resources/META-INF/native-image/org.ballerinalang/ballerina-runtime/resource-config.json b/bvm/ballerina-runtime/src/main/resources/META-INF/native-image/org.ballerinalang/ballerina-runtime/resource-config.json index f6ce63367bfd..4b5e81b83ac8 100644 --- a/bvm/ballerina-runtime/src/main/resources/META-INF/native-image/org.ballerinalang/ballerina-runtime/resource-config.json +++ b/bvm/ballerina-runtime/src/main/resources/META-INF/native-image/org.ballerinalang/ballerina-runtime/resource-config.json @@ -3,6 +3,9 @@ "includes": [ { "pattern": "\\QMETA-INF/axiom.xml\\E" + }, + { + "pattern": "resources/.*" } ] }, diff --git a/bvm/ballerina-runtime/src/main/resources/MessagesBundle.properties b/bvm/ballerina-runtime/src/main/resources/MessagesBundle.properties index 1f0d2a093fd3..14822f24a2d2 100644 --- a/bvm/ballerina-runtime/src/main/resources/MessagesBundle.properties +++ b/bvm/ballerina-runtime/src/main/resources/MessagesBundle.properties @@ -263,8 +263,8 @@ regexp.invalid.unicode.general.category.value = invalid Unicode general category regexp.invalid.unicode.property.value = invalid Unicode property value ''{0}'' regexp.empty.character.class.disallowed = empty character class disallowed regexp.invalid.hex.digit = invalid hexadecimal digit -invalid.method.call = ''{0}'' method is called before module initialization -invalid.function.invocation.call = function ''{0}'' is called before module initialization +function.already.called = function ''{0}'' has already been called +invalid.function.call.before.module.init = function ''{0}'' is called before module initialization config.env.vars.ambiguity = configurable value for variable ''{0}'' clashes with multiple environment variables {1} config.env.variable.ambiguity = configurable value for variable ''{0}'' clashes with variable ''{1}''. Please \ provide the env variable as ''[{2}]'' @@ -274,6 +274,8 @@ config.env.unused.vars = [{0}] unused environment variable config.env.variable.name.ambiguity = configurable environment variable ''{0}'' clashes for variable ''{1}'' with \ variable ''{2}'' no.worker.message.received = no message received from worker ''{0}'' to worker ''{1}'' +invalid.tuple.member.size = the number of members in a tuple value should be greater than the member types of the tuple \ + to perform a ''{0}'' operation #transactions transaction.invalid.checkpoint.value = invalid value provided for checkpoint interval. using default value ''{0}'' diff --git a/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/RuntimeUtilTests.java b/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/RuntimeUtilTests.java index f004dfb8fcb9..2d862f8909be 100644 --- a/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/RuntimeUtilTests.java +++ b/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/RuntimeUtilTests.java @@ -49,8 +49,8 @@ public void testVerifyJavaCompatibilityNegative() { // versions in the format" {compiledVersion, runtimeVersion, supportedVersionRange} String[][] versions = { { "1.8.0_144", "1.7.0_1", "1.8.*" }, { "1.8.0_144", "9", "1.8.*" }, { "9.0.1", "10.0.2.1", "9.0.*" }, { "9", "10.0.2.1", "9.0.*" }, { "10", "9", "10.0.*" } }; - for (int i = 0; i < versions.length; i++) { - testVersionsNegative(versions[i][0], versions[i][1], versions[i][2]); + for (String[] version : versions) { + testVersionsNegative(version[0], version[1], version[2]); } } @@ -59,8 +59,8 @@ public void testVerifyJavaCompatibilityPositive() { // versions in the format" {compiledVersion, runtimeVersion} String[][] versions = { { "1.8.0_144", "1.8.0_144" }, { "1.8.0_144", "1.8.0_221" }, { "9.0_221", "9" }, { "9", "9.0_221" }, { "10.0.1", "10.0.2.1" }, { "10", "10" } }; - for (int i = 0; i < versions.length; i++) { - testVersionsPositive(versions[i][0], versions[i][1]); + for (String[] version : versions) { + testVersionsPositive(version[0], version[1]); } } diff --git a/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/TestUtils.java b/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/TestUtils.java index 7d703830a2b9..d215c5470de0 100644 --- a/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/TestUtils.java +++ b/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/TestUtils.java @@ -25,20 +25,22 @@ import io.ballerina.runtime.internal.util.RuntimeUtils; import java.nio.file.Path; -import java.nio.file.Paths; /** * Utils class for runtime unit tests. * @since 2.0.0 */ -public class TestUtils { +public final class TestUtils { + + private TestUtils() { + } public static Path getConfigPath(String configFileName) { - return Paths.get(RuntimeUtils.USER_DIR, "src", "test", "resources", "config_files", configFileName); + return Path.of(RuntimeUtils.USER_DIR, "src", "test", "resources", "config_files", configFileName); } public static Path getConfigPathForNegativeCases(String configFileName) { - return Paths.get(RuntimeUtils.USER_DIR, "src", "test", "resources", "config_files", "negative", configFileName); + return Path.of(RuntimeUtils.USER_DIR, "src", "test", "resources", "config_files", "negative", configFileName); } public static VariableKey[] getSimpleVariableKeys(Module module) { diff --git a/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/CliProviderTest.java b/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/CliProviderTest.java index e8d3e2f1ca63..71a55055055e 100644 --- a/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/CliProviderTest.java +++ b/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/CliProviderTest.java @@ -211,6 +211,10 @@ public Object[][] unionDataProvider() { PredefinedTypes.TYPE_DECIMAL), true); UnionType floatBoolen = TypeCreator.createUnionType(List.of(PredefinedTypes.TYPE_FLOAT, PredefinedTypes.TYPE_BOOLEAN), true); + UnionType intNull = TypeCreator.createUnionType(List.of(PredefinedTypes.TYPE_INT, + PredefinedTypes.TYPE_NULL), true); + UnionType boolenNull = TypeCreator.createUnionType(List.of(PredefinedTypes.TYPE_BOOLEAN, + PredefinedTypes.TYPE_NULL), true); return new Object[][]{ {"stringInt", getIntersectionType(ROOT_MODULE, stringInt), strVal, "-CstringInt=test"}, {"intFloat", getIntersectionType(ROOT_MODULE, intFloat), 2.2d, "-CintFloat=2.2"}, @@ -218,6 +222,8 @@ public Object[][] unionDataProvider() { {"intBoolean", getIntersectionType(ROOT_MODULE, intBoolean), 2L, "-CintBoolean=2"}, {"intDecimal", getIntersectionType(ROOT_MODULE, intDecimal), decimalVal, "-CintDecimal=3.23"}, {"floatBoolen", getIntersectionType(ROOT_MODULE, floatBoolen), true, "-CfloatBoolen=true"}, + {"intNull", getIntersectionType(ROOT_MODULE, intNull), 87L, "-CintNull=87"}, + {"boolenNull", getIntersectionType(ROOT_MODULE, boolenNull), true, "-CboolenNull=true"}, }; } diff --git a/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/ConfigTest.java b/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/ConfigTest.java index 16ecd652a26f..9807d9640e7e 100644 --- a/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/ConfigTest.java +++ b/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/ConfigTest.java @@ -258,4 +258,23 @@ public void testEnvVarUnsupportedErrors(String variableName, Type type, String e } } + + @Test + public void testCliWhenUnsupportedTypesWithinToml() { + ArrayType arrayType = TypeCreator.createArrayType(TYPE_STRING); + VariableKey v1 = new VariableKey(module, "v1", PredefinedTypes.TYPE_INT, true); + Type v2Type = new BIntersectionType(module, new Type[]{arrayType, PredefinedTypes.TYPE_READONLY}, + arrayType, 0, true); + VariableKey v2 = new VariableKey(module, "v2", v2Type, true); + RuntimeDiagnosticLog diagnosticLog = new RuntimeDiagnosticLog(); + ConfigResolver configResolver = + new ConfigResolver(Map.ofEntries(Map.entry(module, new VariableKey[]{v1, v2})), diagnosticLog, + List.of(new CliProvider(ROOT_MODULE, "-CmyOrg.test_module.v1=87"), + new TomlFileProvider(ROOT_MODULE, + getConfigPath("UnsupportedCLITypeConfig.toml"), Set.of(module)))); + Map configValueMap = configResolver.resolveConfigs(); + Assert.assertEquals(configValueMap.get(v1).getValue(), 87L); + Assert.assertEquals(configValueMap.get(v2).getValue().toString(), "[\"hello\",\"world\"]"); + Assert.assertEquals(0, diagnosticLog.getErrorCount()); + } } diff --git a/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/TomlProviderTest.java b/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/TomlProviderTest.java index 2add5b5e96d1..3ab6dbf9311c 100644 --- a/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/TomlProviderTest.java +++ b/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/TomlProviderTest.java @@ -539,8 +539,12 @@ public void testTomlProviderWithString() { VariableKey booleanArr = new VariableKey(ROOT_MODULE, "booleanArr", new BIntersectionType(ROOT_MODULE, new BType[]{}, TypeCreator.createArrayType(PredefinedTypes.TYPE_BOOLEAN), 0, false), true); configVarMap.put(ROOT_MODULE, new VariableKey[]{intVar, stringVar, stringArr, booleanArr}); - String tomlContent = "[rootOrg.test_module]\nintVar = 33\nstringVar = \"xyz\"\n" + - "stringArr = [\"aa\", \"bb\", \"cc\"]\nbooleanArr = [false, true, true, false]"; + String tomlContent = """ + [rootOrg.test_module] + intVar = 33 + stringVar = "xyz" + stringArr = ["aa", "bb", "cc"] + booleanArr = [false, true, true, false]"""; ConfigResolver configResolver = new ConfigResolver(configVarMap, new RuntimeDiagnosticLog(), List.of(new TomlContentProvider(ROOT_MODULE, tomlContent, configVarMap.keySet()))); Map configValueMap = configResolver.resolveConfigs(); diff --git a/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/negative/ConfigNegativeTest.java b/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/negative/ConfigNegativeTest.java index 8ece72e3eb8f..a3a2fc0cd202 100644 --- a/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/negative/ConfigNegativeTest.java +++ b/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/negative/ConfigNegativeTest.java @@ -173,17 +173,19 @@ public Object[][] configErrorCases() { // invalid toml but valid cli {new String[]{"-Corg.mod1.intVar=2"}, "Invalid.toml", new HashMap<>(), new VariableKey[]{new VariableKey(MODULE, "intVar", PredefinedTypes.TYPE_INT, true)}, 0, 1, - new String[]{ - "warning: invalid TOML file : \n" + - "[Invalid.toml:(3:1,3:1)] missing equal token\n" + - "[Invalid.toml:(3:1,3:1)] missing value\n"}}, + new String[]{""" + warning: invalid TOML file :\s + [Invalid.toml:(3:1,3:1)] missing equal token + [Invalid.toml:(3:1,3:1)] missing value + """}}, // invalid toml but valid env var {new String[]{}, "Invalid.toml", Map.of("BAL_CONFIG_VAR_ORG_MOD1_INTVAR", "2"), new VariableKey[]{new VariableKey(MODULE, "intVar", PredefinedTypes.TYPE_INT, true)}, 0, 1, - new String[]{ - "warning: invalid TOML file : \n" + - "[Invalid.toml:(3:1,3:1)] missing equal token\n" + - "[Invalid.toml:(3:1,3:1)] missing value\n"}}, + new String[]{""" + warning: invalid TOML file :\s + [Invalid.toml:(3:1,3:1)] missing equal token + [Invalid.toml:(3:1,3:1)] missing value + """}}, // supported toml type but not cli type and cli value given {new String[]{"-Corg.mod1.intArr=3"}, "MatchedTypeValues.toml", new HashMap<>(), new VariableKey[]{new VariableKey(MODULE, "intArr", diff --git a/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/negative/TomlProviderNegativeTest.java b/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/negative/TomlProviderNegativeTest.java index 57414a5d5d46..253b87ce7efb 100644 --- a/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/negative/TomlProviderNegativeTest.java +++ b/bvm/ballerina-runtime/src/test/java/io/ballerina/runtime/test/config/negative/TomlProviderNegativeTest.java @@ -84,10 +84,12 @@ public Object[][] getPathErrorTests() { {"NoConfig.toml", "warning: configuration file is not found in path '" + getConfigPathForNegativeCases("NoConfig.toml") + "'", 1}, - {"InvalidConfig.toml", "warning: invalid TOML file : \n" + - "[InvalidConfig.toml:(1:8,1:8)] missing identifier\n" + - "[InvalidConfig.toml:(1:26,1:26)] missing identifier\n" + - "[InvalidConfig.toml:(1:27,1:27)] missing identifier\n", 1}, + {"InvalidConfig.toml", """ + warning: invalid TOML file :\s + [InvalidConfig.toml:(1:8,1:8)] missing identifier + [InvalidConfig.toml:(1:26,1:26)] missing identifier + [InvalidConfig.toml:(1:27,1:27)] missing identifier + """, 1}, {"InvalidByteRange.toml", "error: [InvalidByteRange.toml:(2:11,2:14)] value provided for byte " + "variable 'byteVar' is out of range. Expected range is (0-255), found '355'", 0} }; @@ -456,8 +458,10 @@ public void testClashingOrgSubModules() { VariableKey[] clashingVariableKeys = getSimpleVariableKeys(clashingModule); Map variableMap = Map.ofEntries(Map.entry(subModule, subVariableKeys), Map.entry(clashingModule, clashingVariableKeys)); - String errorMsg = "warning: invalid TOML file : \n" + - "[ClashingOrgModuleError1.toml:(5:1,7:19)] existing node 'foo'\n"; + String errorMsg = """ + warning: invalid TOML file :\s + [ClashingOrgModuleError1.toml:(5:1,7:19)] existing node 'foo' + """; RuntimeDiagnosticLog diagnosticLog = new RuntimeDiagnosticLog(); ConfigResolver configResolver = new ConfigResolver(variableMap, diagnosticLog, List.of(new TomlFileProvider(TomlProviderNegativeTest.ROOT_MODULE, diff --git a/bvm/ballerina-runtime/src/test/resources/config_files/UnsupportedCLITypeConfig.toml b/bvm/ballerina-runtime/src/test/resources/config_files/UnsupportedCLITypeConfig.toml new file mode 100644 index 000000000000..ed6a86aa838e --- /dev/null +++ b/bvm/ballerina-runtime/src/test/resources/config_files/UnsupportedCLITypeConfig.toml @@ -0,0 +1,2 @@ +[myOrg.test_module] +v2 = ["hello", "world"] diff --git a/cli/ballerina-cli/build.gradle b/cli/ballerina-cli/build.gradle index 90b35005a054..d788d007c3be 100644 --- a/cli/ballerina-cli/build.gradle +++ b/cli/ballerina-cli/build.gradle @@ -15,8 +15,10 @@ * */ -apply from: "$rootDir/gradle/javaProject.gradle" -apply from: "$rootDir/gradle/ballerinaLangLibLoad.gradle" +plugins { + id 'javaProject' + id 'ballerinaLangLibLoad' +} configurations { testImplementation.exclude group: 'org.slf4j', module: 'slf4j-log4j12' @@ -38,9 +40,12 @@ dependencies { implementation project(':ballerina-runtime') implementation project(':ballerina-tools-api') implementation project(':central-client') - implementation 'info.picocli:picocli' - implementation "org.apache.commons:commons-compress:${project.apacheCommonsCompressVersion}" - implementation "com.google.code.gson:gson:${project.gsonVersion}" + implementation libs.picocli + implementation(libs.apache.commons.compress) { + exclude group: 'commons-codec', module: 'commons-codec' + exclude group: 'org.apache.commons', module: 'commons-lang3' + } + implementation libs.gson implementation project(':docerina') implementation project(':testerina:testerina-core') implementation project(':testerina:testerina-runtime') @@ -49,23 +54,19 @@ dependencies { implementation project(':toml-parser') implementation project(':identifier-util') testImplementation project(':ballerina-test-utils') - implementation 'org.ow2.asm:asm' - implementation "org.ow2.asm:asm-commons:${project.ow2AsmCommonsVersion}" - implementation "org.jacoco:org.jacoco.core:${project.jacocoVersion}" - implementation "org.jacoco:org.jacoco.report:${project.jacocoVersion}" - implementation group: 'org.jacoco', name: 'org.jacoco.core', version: "${project.jacocoVersion}" - implementation group: 'org.jacoco', name: 'org.jacoco.report', version: "${project.jacocoVersion}" - implementation group: 'org.ow2.asm', name: 'asm', version: "${project.ow2AsmVersion}" - implementation group: 'org.ow2.asm', name: 'asm-commons', version: "${project.ow2AsmCommonsVersion}" - implementation group: 'org.ow2.asm', name: 'asm-tree', version: "${project.ow2AsmTreeVersion}" - implementation 'commons-io:commons-io' - - testImplementation "org.testng:testng:${project.testngVersion}" - testImplementation "org.mockito:mockito-core:${project.mockitoCoreVersion}" - testImplementation 'org.mockito:mockito-testng' - testImplementation 'commons-io:commons-io' - testImplementation "commons-codec:commons-codec:${project.commonsCodecVersion}" - testImplementation "org.jline:jline:${project.jlineVersion}" + implementation libs.ow2.asm + implementation libs.ow2.asm.commons + implementation libs.ow2.asm.tree + implementation libs.jacoco.core + implementation libs.jacoco.report + implementation libs.commons.io + + testImplementation libs.testng + testImplementation libs.mockito.core + testImplementation libs.mockito.testng + testImplementation libs.commons.io + testImplementation libs.commons.codec + testImplementation libs.jline distributionBala project(path: ':ballerina-langlib:test', configuration: 'distributionBala') distributionBala project(path: ':testerina:testerina-core', configuration: 'distributionBala') @@ -89,23 +90,23 @@ dependencies { compilerPluginJar project(':project-api-test-artifact:diagnostic-utils-lib') } -task createTestDistributionCache(type: Copy) { +tasks.register('createTestDistributionCache', Copy) { dependsOn configurations.distributionBala from configurations.distributionBala into "$buildDir/repo" } -task copyCompilerPluginJars(type: Copy) { +tasks.register('copyCompilerPluginJars', Copy) { from configurations.compilerPluginJar into "$buildDir/compiler-plugin-jars" } -task copyProfilerResources(type: Copy) { +tasks.register('copyProfilerResources', Copy) { from project(':jballerina-tools').file('resources/profiler') into "$buildDir/resources/profiler" } -task createTestBre(type: Copy) { +tasks.register('createTestBre', Copy) { from configurations.balRt from configurations.testRt from configurations.testCore @@ -137,13 +138,18 @@ compileJava { dependsOn ':testerina:testerina-core:copyInteropImports' inputs.property("moduleName", moduleName) doFirst { - options.compilerArgs = [ - '--module-path', classpath.asPath, - ] + options.compilerArgs << '--module-path' << classpath.asPath + classpath = files() + } +} + +javadoc { + doFirst { + options.modulePath = classpath.toList() classpath = files() } } tasks.compileJava.dependsOn(':testerina:testerina-core:copyInteropImports') -tasks.createJavadoc.dependsOn(':testerina:testerina-core:copyInteropImports') +tasks.javadoc.dependsOn(':testerina:testerina-core:copyInteropImports') diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/BLauncherCmd.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/BLauncherCmd.java index bd70b9d5727a..c2449bab214c 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/BLauncherCmd.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/BLauncherCmd.java @@ -72,10 +72,6 @@ public interface BLauncherCmd { * @return usage info for the specified command */ static String getCommandUsageInfo(String commandName) { - if (commandName == null) { - throw LauncherUtils.createUsageExceptionWithHelp("invalid command"); - } - String fileName = "cli-help/ballerina-" + commandName + ".help"; try { return BCompileUtil.readFileAsString(fileName); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/TaskExecutor.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/TaskExecutor.java index 66cdbf801a93..3d36b9db34db 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/TaskExecutor.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/TaskExecutor.java @@ -45,7 +45,7 @@ public void executeTasks(Project project) { * Task executor builder class. */ public static class TaskBuilder { - private TaskExecutor taskExecutor = new TaskExecutor(); + private final TaskExecutor taskExecutor = new TaskExecutor(); public TaskBuilder addTask(Task task) { this.taskExecutor.tasks.add(task); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/AddCommand.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/AddCommand.java index a740c8fbee35..f74f68cd57c8 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/AddCommand.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/AddCommand.java @@ -28,7 +28,6 @@ import java.nio.file.AccessDeniedException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.List; import java.util.Locale; @@ -59,7 +58,7 @@ public class AddCommand implements BLauncherCmd { private String template = "lib"; public AddCommand() { - this.userDir = Paths.get(System.getProperty("user.dir")); + this.userDir = Path.of(System.getProperty("user.dir")); this.errStream = System.err; this.exitWhenFinish = true; CommandUtil.initJarFs(); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/BuildCommand.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/BuildCommand.java index a42387625891..46b63e0cbd84 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/BuildCommand.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/BuildCommand.java @@ -33,14 +33,11 @@ import io.ballerina.projects.directory.BuildProject; import io.ballerina.projects.directory.SingleFileProject; import io.ballerina.projects.util.ProjectConstants; -import io.ballerina.projects.util.ProjectUtils; -import org.ballerinalang.toml.exceptions.SettingsTomlException; import org.wso2.ballerinalang.util.RepoUtils; import picocli.CommandLine; import java.io.PrintStream; import java.nio.file.Path; -import java.nio.file.Paths; import static io.ballerina.cli.cmd.Constants.BUILD_COMMAND; import static io.ballerina.projects.util.ProjectUtils.isProjectUpdated; @@ -58,7 +55,7 @@ public class BuildCommand implements BLauncherCmd { private final boolean exitWhenFinish; public BuildCommand() { - this.projectPath = Paths.get(System.getProperty(ProjectConstants.USER_DIR)); + this.projectPath = Path.of(System.getProperty(ProjectConstants.USER_DIR)); this.outStream = System.out; this.errStream = System.err; this.exitWhenFinish = true; @@ -72,6 +69,16 @@ public BuildCommand() { this.offline = true; } + BuildCommand(Path projectPath, PrintStream outStream, PrintStream errStream, boolean exitWhenFinish, + Boolean optimizeDependencyCompilation) { + this.projectPath = projectPath; + this.outStream = outStream; + this.errStream = errStream; + this.exitWhenFinish = exitWhenFinish; + this.optimizeDependencyCompilation = optimizeDependencyCompilation; + this.offline = true; + } + BuildCommand(Path projectPath, PrintStream outStream, PrintStream errStream, boolean exitWhenFinish, boolean dumpBuildTime) { this.projectPath = projectPath; @@ -155,6 +162,10 @@ public BuildCommand() { @CommandLine.Option(names = "--cloud", description = "Enable cloud artifact generation") private String cloud; + @CommandLine.Option(names = "--show-dependency-diagnostics", description = "Show the diagnostics " + + "generated by the dependencies") + private Boolean showDependencyDiagnostics; + @CommandLine.Option(names = "--remote-management", description = "enable service management tools in " + "the executable JAR file(s).") private Boolean remoteManagement; @@ -195,6 +206,11 @@ public BuildCommand() { "generation") private String graalVMBuildOptions; + @CommandLine.Option(names = "--optimize-dependency-compilation", hidden = true, + description = "experimental memory optimization for large projects") + private Boolean optimizeDependencyCompilation; + + @Override public void execute() { long start = 0; if (this.helpFlag) { @@ -256,20 +272,8 @@ public void execute() { } } - // If project is empty - if (ProjectUtils.isProjectEmpty(project)) { - CommandUtil.printError(this.errStream, "package is empty. Please add at least one .bal file.", null, - false); - CommandUtil.exitError(this.exitWhenFinish); - return; - } - // Validate Settings.toml file - try { - RepoUtils.readSettings(); - } catch (SettingsTomlException e) { - this.outStream.println("warning: " + e.getMessage()); - } + RepoUtils.readSettings(); if (!project.buildOptions().nativeImage() && !project.buildOptions().graalVMBuildOptions().isEmpty()) { this.outStream.println("WARNING: Additional GraalVM build options are ignored since graalvm " + @@ -289,7 +293,7 @@ public void execute() { // compile the modules .addTask(new CompileTask(outStream, errStream, false, true, isPackageModified, buildOptions.enableCache())) - .addTask(new CreateExecutableTask(outStream, this.output)) + .addTask(new CreateExecutableTask(outStream, this.output, null, false)) .addTask(new DumpBuildTimeTask(outStream), !project.buildOptions().dumpBuildTime()) .build(); @@ -320,7 +324,9 @@ private BuildOptions constructBuildOptions() { .setEnableCache(enableCache) .setNativeImage(nativeImage) .disableSyntaxTreeCaching(disableSyntaxTreeCaching) - .setGraalVMBuildOptions(graalVMBuildOptions); + .setGraalVMBuildOptions(graalVMBuildOptions) + .setShowDependencyDiagnostics(showDependencyDiagnostics) + .setOptimizeDependencyCompilation(optimizeDependencyCompilation); if (targetDir != null) { buildOptionsBuilder.targetDir(targetDir.toString()); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/CleanCommand.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/CleanCommand.java index 6d28d9dbb972..6e92fe62696b 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/CleanCommand.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/CleanCommand.java @@ -29,7 +29,6 @@ import java.io.PrintStream; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import static io.ballerina.cli.cmd.Constants.CLEAN_COMMAND; @@ -42,7 +41,7 @@ public class CleanCommand implements BLauncherCmd { private final PrintStream outStream; private final Path projectPath; - private boolean exitWhenFinish; + private final boolean exitWhenFinish; @CommandLine.Option(names = {"--help", "-h"}, hidden = true) private boolean helpFlag; @@ -57,7 +56,7 @@ public CleanCommand(Path projectPath, boolean exitWhenFinish) { } public CleanCommand() { - this.projectPath = Paths.get(System.getProperty(ProjectConstants.USER_DIR)); + this.projectPath = Path.of(System.getProperty(ProjectConstants.USER_DIR)); this.outStream = System.out; this.exitWhenFinish = true; } @@ -77,7 +76,20 @@ public void execute() { return; } - if (this.targetDir == null) { + if (this.targetDir != null) { + if (Files.notExists(this.targetDir)) { + CommandUtil.printError(this.outStream, + "provided target directory '" + this.targetDir + "' does not exist.", + null, false); + } else if (!Files.isDirectory(this.targetDir)) { + CommandUtil.printError(this.outStream, + "provided target path '" + this.targetDir + "' is not a directory.", + null, false); + } else { + ProjectUtils.deleteDirectory(this.targetDir); + this.outStream.println("Successfully deleted '" + this.targetDir + "'."); + } + } else { try { Project project = BuildProject.load(this.projectPath); this.targetDir = project.targetDir(); @@ -86,23 +98,13 @@ public void execute() { CommandUtil.exitError(this.exitWhenFinish); return; } + if (Files.exists(this.targetDir)) { + ProjectUtils.deleteDirectory(this.targetDir); + this.outStream.println("Successfully deleted '" + this.targetDir + "'."); + } } - // Delete the target directory - if (Files.notExists(this.targetDir)) { - CommandUtil.printError(this.outStream, - "provided target directory '" + this.targetDir + "' does not exist.", - null, false); - } else if (!Files.isDirectory(this.targetDir)) { - CommandUtil.printError(this.outStream, - "provided target path '" + this.targetDir + "' is not a directory.", - null, false); - } else { - ProjectUtils.deleteDirectory(this.targetDir); - this.outStream.println("Successfully deleted '" + this.targetDir + "'."); - } - - //delete the generated directory + // delete the generated directory Path generatedDir; try { Project project = BuildProject.load(this.projectPath); @@ -112,9 +114,7 @@ public void execute() { CommandUtil.exitError(this.exitWhenFinish); return; } - if (Files.notExists(generatedDir)) { - this.outStream.println("Existing generated directory was not found"); - } else { + if (Files.exists(generatedDir)) { ProjectUtils.deleteDirectory(generatedDir); this.outStream.println("Successfully deleted '" + generatedDir + "'."); } diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/CommandUtil.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/CommandUtil.java index 7e6f4a510bbe..7e2025aa2346 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/CommandUtil.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/CommandUtil.java @@ -21,6 +21,7 @@ import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import io.ballerina.projects.BuildOptions; import io.ballerina.projects.JBallerinaBackend; import io.ballerina.projects.JvmTarget; import io.ballerina.projects.Package; @@ -48,7 +49,6 @@ import org.ballerinalang.central.client.CentralClientConstants; import org.ballerinalang.central.client.exceptions.CentralClientException; import org.ballerinalang.central.client.exceptions.PackageAlreadyExistsException; -import org.ballerinalang.toml.exceptions.SettingsTomlException; import org.wso2.ballerinalang.util.RepoUtils; import java.io.FileInputStream; @@ -64,7 +64,6 @@ import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.util.ArrayList; @@ -103,7 +102,8 @@ * * @since 2.0.0 */ -public class CommandUtil { +public final class CommandUtil { + public static final String ORG_NAME = "ORG_NAME"; public static final String PKG_NAME = "PKG_NAME"; public static final String DIST_VERSION = "DIST_VERSION"; @@ -125,6 +125,9 @@ public class CommandUtil { private static boolean exitWhenFinish; private static String platform; + private CommandUtil() { + } + static void setPrintStream(PrintStream errStream) { CommandUtil.errStream = errStream; } @@ -294,7 +297,7 @@ private static void addModules(Path balaPath, Path projectPath, String packageNa Path moduleMdDirRoot = balaPath.resolve("docs").resolve(ProjectConstants.MODULES_ROOT); List modulesList; try (Stream pathStream = Files.list(modulesRoot)) { - modulesList = pathStream.collect(Collectors.toList()); + modulesList = pathStream.toList(); } for (Path moduleRoot : modulesList) { Path moduleDir = Optional.of(moduleRoot.getFileName()).get(); @@ -326,7 +329,7 @@ private static void copyIcon(Path balaPath, Path projectPath) { try (Stream pathStream = Files.walk(docsPath, 1)) { List icon = pathStream .filter(FileSystems.getDefault().getPathMatcher("glob:**.png")::matches) - .collect(Collectors.toList()); + .toList(); if (!icon.isEmpty()) { Path projectDocsDir = projectPath.resolve(ProjectConstants.BALA_DOCS_DIR); Files.createDirectory(projectDocsDir); @@ -379,9 +382,8 @@ private static Path updateModuleDirectoryNaming(Path includePath, Path balaPath, String destinationDirName = moduleDirName.split(templatePkgName + ProjectConstants.DOT, 2)[1]; Path includePathRelativeToModuleRoot = modulesDirPath.resolve(moduleRootPath) .relativize(absoluteIncludePath); - Path updatedIncludePath = Paths.get(ProjectConstants.MODULES_ROOT).resolve(destinationDirName) + return Path.of(ProjectConstants.MODULES_ROOT).resolve(destinationDirName) .resolve(includePathRelativeToModuleRoot); - return updatedIncludePath; } return includePath; } @@ -450,28 +452,20 @@ public static void initPackageFromCentral(Path balaCache, Path projectPath, Stri private static void pullPackageFromRemote(String orgName, String packageName, String version, Path destination) throws CentralClientException { String supportedPlatform = Arrays.stream(JvmTarget.values()) - .map(target -> target.code()) + .map(JvmTarget::code) .collect(Collectors.joining(",")); Settings settings; - try { - settings = readSettings(); - // Ignore Settings.toml diagnostics in the pull command - } catch (SettingsTomlException e) { - // Ignore 'Settings.toml' parsing errors and return empty Settings object - settings = Settings.from(); - } + settings = readSettings(); + // Ignore Settings.toml diagnostics in the pull command + CentralAPIClient client = new CentralAPIClient(RepoUtils.getRemoteRepoURL(), initializeProxy(settings.getProxy()), settings.getProxy().username(), settings.getProxy().password(), getAccessTokenOfCLI(settings), settings.getCentral().getConnectTimeout(), settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(), - settings.getCentral().getCallTimeout()); - try { - client.pullPackage(orgName, packageName, version, destination, supportedPlatform, - RepoUtils.getBallerinaVersion(), false); - } catch (CentralClientException e) { - throw e; - } + settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries()); + client.pullPackage(orgName, packageName, version, destination, supportedPlatform, + RepoUtils.getBallerinaVersion(), false); } public static void writeBallerinaToml(Path balTomlPath, PackageJson packageJson, @@ -485,7 +479,7 @@ public static void writeBallerinaToml(Path balTomlPath, PackageJson packageJson, Files.writeString(balTomlPath, "\nversion = \"" + packageJson.getVersion() + "\"", StandardOpenOption.APPEND); List newModuleNames = packageJson.getExport().stream().map(module -> - module.replaceFirst(packageJson.getName(), packageName)).collect(Collectors.toList()); + module.replaceFirst(packageJson.getName(), packageName)).toList(); StringJoiner stringJoiner = new StringJoiner(","); for (String newModuleName : newModuleNames) { @@ -516,8 +510,8 @@ public static void writeBallerinaToml(Path balTomlPath, PackageJson packageJson, JsonObject dependenciesObj = (JsonObject) dependencies; if (null == dependenciesObj.get("scope")) { String libPath = dependenciesObj.get("path").getAsString(); - Path libName = Optional.of(Paths.get(libPath).getFileName()).get(); - Path libRelPath = Paths.get("libs", libName.toString()); + Path libName = Optional.of(Path.of(libPath).getFileName()).get(); + Path libRelPath = Path.of("libs", libName.toString()); Files.writeString(balTomlPath, "\npath = \"" + libRelPath + "\"", StandardOpenOption.APPEND); } @@ -553,11 +547,13 @@ public static void writeDependenciesToml(Path projectPath, DependencyGraphJson t PackageJson templatePackageJson) throws IOException { Path depsTomlPath = projectPath.resolve(DEPENDENCIES_TOML); - String autoGenCode = "# AUTO-GENERATED FILE. DO NOT MODIFY.\n" + - "\n" + - "# This file is auto-generated by Ballerina for managing dependency versions.\n" + - "# It should not be modified by hand.\n" + - "\n"; + String autoGenCode = """ + # AUTO-GENERATED FILE. DO NOT MODIFY. + + # This file is auto-generated by Ballerina for managing dependency versions. + # It should not be modified by hand. + + """; Files.writeString(depsTomlPath, autoGenCode, StandardOpenOption.APPEND); String balTomlVersion = "[ballerina]\n" + "dependencies-toml-version = \"" + ProjectConstants.DEPENDENCIES_TOML_VERSION + "\"\n" + @@ -776,11 +772,9 @@ private static void writePackageAttributeValue(Path balTomlPath, String attribut public static String findPkgName(String template) { // Split the template in to parts String[] orgSplit = template.split("/"); - String packageName = ""; String packagePart = (orgSplit.length > 1) ? orgSplit[1] : ""; String[] pkgSplit = packagePart.split(":"); - packageName = pkgSplit[0].trim(); - return packageName; + return pkgSplit[0].trim(); } /** @@ -852,7 +846,7 @@ private static void createDefaultGitignore(Path path) throws IOException { } if (Files.size(gitignore) == 0) { String defaultGitignore = FileUtils.readFileAsString(NEW_CMD_DEFAULTS + "/" + GITIGNORE); - Files.write(gitignore, defaultGitignore.getBytes(StandardCharsets.UTF_8)); + Files.writeString(gitignore, defaultGitignore); } } @@ -864,7 +858,7 @@ private static void createDefaultDevContainer(Path path) throws IOException { if (Files.size(devContainer) == 0) { String defaultDevContainer = FileUtils.readFileAsString(NEW_CMD_DEFAULTS + "/" + DEVCONTAINER); defaultDevContainer = defaultDevContainer.replace("latest", RepoUtils.getBallerinaVersion()); - Files.write(devContainer, defaultDevContainer.getBytes(StandardCharsets.UTF_8)); + Files.writeString(devContainer, defaultDevContainer); } } @@ -876,21 +870,22 @@ private static void createDefaultDevContainer(Path path) throws IOException { public static List getTemplates() { try { Path templateDir = getTemplatePath(); - Stream walk = Files.walk(templateDir, 1); + try (Stream walk = Files.walk(templateDir, 1)) { - List templates = walk.filter(Files::isDirectory) + List templates = walk.filter(Files::isDirectory) .filter(directory -> !templateDir.equals(directory)) - .filter(directory -> directory.getFileName() != null) .map(directory -> directory.getFileName()) - .map(fileName -> fileName.toString()) - .collect(Collectors.toList()); - - if (null != jarFs) { - return templates.stream().map(t -> t - .replace(jarFs.getSeparator(), "")) - .collect(Collectors.toList()); - } else { - return templates; + .filter(Objects::nonNull) + .map(Path::toString) + .toList(); + + if (null != jarFs) { + return templates.stream().map(t -> t + .replace(jarFs.getSeparator(), "")) + .toList(); + } else { + return templates; + } } } catch (IOException | URISyntaxException e) { @@ -911,7 +906,7 @@ private static Path getTemplatePath() throws URISyntaxException { final String[] array = uri.toString().split("!"); return jarFs.getPath(array[1]); } else { - return Paths.get(uri); + return Path.of(uri); } } @@ -954,10 +949,10 @@ public static void initPackage(Path path, String packageName) throws IOException String defaultManifest = FileUtils.readFileAsString(NEW_CMD_DEFAULTS + "/" + "manifest-app.toml"); // replace manifest distribution with a guessed value defaultManifest = defaultManifest - .replaceAll(ORG_NAME, ProjectUtils.guessOrgName()) - .replaceAll(PKG_NAME, guessPkgName(packageName, "app")) - .replaceAll(DIST_VERSION, RepoUtils.getBallerinaShortVersion()); - Files.write(ballerinaToml, defaultManifest.getBytes(StandardCharsets.UTF_8)); + .replace(ORG_NAME, ProjectUtils.guessOrgName()) + .replace(PKG_NAME, guessPkgName(packageName, "app")) + .replace(DIST_VERSION, RepoUtils.getBallerinaShortVersion()); + Files.writeString(ballerinaToml, defaultManifest); } private static void initLibPackage(Path path, String packageName) throws IOException { @@ -966,11 +961,11 @@ private static void initLibPackage(Path path, String packageName) throws IOExcep String defaultManifest = FileUtils.readFileAsString(NEW_CMD_DEFAULTS + "/" + "manifest-lib.toml"); // replace manifest org and name with a guessed value. - defaultManifest = defaultManifest.replaceAll(ORG_NAME, ProjectUtils.guessOrgName()) - .replaceAll(PKG_NAME, guessPkgName(packageName, "lib")) - .replaceAll(DIST_VERSION, RepoUtils.getBallerinaShortVersion()); + defaultManifest = defaultManifest.replace(ORG_NAME, ProjectUtils.guessOrgName()) + .replace(PKG_NAME, guessPkgName(packageName, "lib")) + .replace(DIST_VERSION, RepoUtils.getBallerinaShortVersion()); - write(ballerinaToml, defaultManifest.getBytes(StandardCharsets.UTF_8)); + Files.writeString(ballerinaToml, defaultManifest); // Create Package.md String packageMd = FileUtils.readFileAsString(NEW_CMD_DEFAULTS + "/Package.md"); @@ -990,21 +985,21 @@ private static void initToolPackage(Path path, String packageName) throws IOExce String defaultManifest = FileUtils.readFileAsString(NEW_CMD_DEFAULTS + "/" + "manifest-app.toml"); defaultManifest = defaultManifest - .replaceAll(ORG_NAME, ProjectUtils.guessOrgName()) - .replaceAll(PKG_NAME, guessPkgName(packageName, TOOL_DIR)) - .replaceAll(DIST_VERSION, RepoUtils.getBallerinaShortVersion()); - Files.write(ballerinaToml, defaultManifest.getBytes(StandardCharsets.UTF_8)); + .replace(ORG_NAME, ProjectUtils.guessOrgName()) + .replace(PKG_NAME, guessPkgName(packageName, TOOL_DIR)) + .replace(DIST_VERSION, RepoUtils.getBallerinaShortVersion()); + Files.writeString(ballerinaToml, defaultManifest); Path balToolToml = path.resolve(ProjectConstants.BAL_TOOL_TOML); Files.createFile(balToolToml); String balToolManifest = FileUtils.readFileAsString(NEW_CMD_DEFAULTS + "/" + "manifest-tool.toml"); - balToolManifest = balToolManifest.replaceAll(TOOL_ID, guessPkgName(packageName, TOOL_DIR)); + balToolManifest = balToolManifest.replace(TOOL_ID, guessPkgName(packageName, TOOL_DIR)); - write(balToolToml, balToolManifest.getBytes(StandardCharsets.UTF_8)); + Files.writeString(balToolToml, balToolManifest); } - protected static PackageVersion findLatest(List packageVersions) { + private static PackageVersion findLatest(List packageVersions) { if (packageVersions.isEmpty()) { return null; } @@ -1015,7 +1010,7 @@ protected static PackageVersion findLatest(List packageVersions) return latestVersion; } - protected static PackageVersion getLatest(PackageVersion v1, PackageVersion v2) { + private static PackageVersion getLatest(PackageVersion v1, PackageVersion v2) { SemanticVersion semVer1 = v1.value(); SemanticVersion semVer2 = v2.value(); boolean isV1PreReleaseVersion = semVer1.isPreReleaseVersion(); @@ -1030,18 +1025,16 @@ protected static PackageVersion getLatest(PackageVersion v1, PackageVersion v2) public static List getPackageVersions(Path balaPackagePath) { List versions = new ArrayList<>(); if (Files.exists(balaPackagePath)) { - Stream collectVersions; - try { - collectVersions = Files.list(balaPackagePath); + try (Stream collectVersions = Files.list(balaPackagePath)) { + versions.addAll(collectVersions.toList()); } catch (IOException e) { throw new RuntimeException("Error while accessing Distribution cache: " + e.getMessage()); } - versions.addAll(collectVersions.collect(Collectors.toList())); } return pathToVersions(versions); } - protected static List pathToVersions(List versions) { + private static List pathToVersions(List versions) { List availableVersions = new ArrayList<>(); versions.stream().map(path -> Optional.ofNullable(path) .map(Path::getFileName) @@ -1090,11 +1083,13 @@ private static String removeLastCharacter(String str) { public static String checkTemplateFilesExists(String template, Path packagePath) throws URISyntaxException, IOException { Path templateDir = getTemplatePath().resolve(template); - Stream paths = Files.list(templateDir); - List templateFilePathList = paths.collect(Collectors.toList()); + List templateFilePathList; + try (Stream paths = Files.list(templateDir)) { + templateFilePathList = paths.toList(); + } StringBuilder existingFiles = new StringBuilder(); for (Path path : templateFilePathList) { - Optional fileNameOptional = Optional.ofNullable(path.getFileName()).map(path1 -> path1.toString()); + Optional fileNameOptional = Optional.ofNullable(path.getFileName()).map(Path::toString); if (fileNameOptional.isPresent()) { String fileName = fileNameOptional.get(); if (!fileName.endsWith(ProjectConstants.BLANG_SOURCE_EXT) && @@ -1131,7 +1126,9 @@ public static String checkPackageFilesExists(Path packagePath) { */ public static boolean balFilesExists(Path packagePath) throws IOException { //Only skip the bal file to be created if any other .bal files exists - return Files.list(packagePath).anyMatch(path -> path.toString().endsWith(ProjectConstants.BLANG_SOURCE_EXT)); + try (Stream list = Files.list(packagePath)) { + return list.anyMatch(path -> path.toString().endsWith(ProjectConstants.BLANG_SOURCE_EXT)); + } } /** @@ -1156,12 +1153,14 @@ static String getLatestVersion(List versions) { * @param orgName org name of the dependent package * @param packageName name of the dependent package * @param version version of the dependent package + * @param buildOptions build options {sticky, offline} * @return true if the dependent package compilation has errors */ - static boolean pullDependencyPackages(String orgName, String packageName, String version) { + static boolean pullDependencyPackages(String orgName, String packageName, String version, + BuildOptions buildOptions, String repository) { Path ballerinaUserHomeDirPath = ProjectUtils.createAndGetHomeReposPath(); Path centralRepositoryDirPath = ballerinaUserHomeDirPath.resolve(ProjectConstants.REPOSITORIES_DIR) - .resolve(ProjectConstants.CENTRAL_REPOSITORY_CACHE_NAME); + .resolve(repository); Path balaDirPath = centralRepositoryDirPath.resolve(ProjectConstants.BALA_DIR_NAME); Path balaPath = ProjectUtils.getPackagePath(balaDirPath, orgName, packageName, version); String ballerinaShortVersion = RepoUtils.getBallerinaShortVersion(); @@ -1170,7 +1169,7 @@ static boolean pullDependencyPackages(String orgName, String packageName, String ProjectEnvironmentBuilder defaultBuilder = ProjectEnvironmentBuilder.getDefaultBuilder(); defaultBuilder.addCompilationCacheFactory(new FileSystemCache.FileSystemCacheFactory(cacheDir)); - BalaProject balaProject = BalaProject.loadProject(defaultBuilder, balaPath); + BalaProject balaProject = BalaProject.loadProject(defaultBuilder, balaPath, buildOptions); // Delete package cache if available Path packageCacheDir = cacheDir.resolve(orgName).resolve(packageName).resolve(version); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/Constants.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/Constants.java index f07d647eaa9f..ea52c012f1d0 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/Constants.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/Constants.java @@ -22,7 +22,8 @@ * * @since 2.0.0 */ -public class Constants { +public final class Constants { + public static final String BUILD_COMMAND = "build"; public static final String RUN_COMMAND = "run"; public static final String DOC_COMMAND = "doc"; @@ -61,4 +62,7 @@ public class Constants { public static final String DEBUG_OPTION = "--debug"; public static final String VERSION_SHORT_OPTION = "-v"; public static final String HELP_SHORT_OPTION = "-h"; + + private Constants() { + } } diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/DeprecateCommand.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/DeprecateCommand.java index 4218007a2574..0fd0360d1e4c 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/DeprecateCommand.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/DeprecateCommand.java @@ -23,7 +23,6 @@ import io.ballerina.projects.Settings; import org.ballerinalang.central.client.CentralAPIClient; import org.ballerinalang.central.client.exceptions.CentralClientException; -import org.ballerinalang.toml.exceptions.SettingsTomlException; import org.wso2.ballerinalang.util.RepoUtils; import picocli.CommandLine; @@ -43,9 +42,9 @@ @CommandLine.Command(name = DEPRECATE_COMMAND, description = "Deprecate a package in Ballerina Central") public class DeprecateCommand implements BLauncherCmd { - private PrintStream outStream; - private PrintStream errStream; - private boolean exitWhenFinish; + private final PrintStream outStream; + private final PrintStream errStream; + private final boolean exitWhenFinish; private static final String USAGE_TEXT = "bal deprecate {/:} [OPTIONS]"; @@ -157,13 +156,9 @@ public void setParentCmdParser(CommandLine parentCmdParser) { private void deprecateInCentral(String packageInfo) { try { Settings settings; - try { - settings = RepoUtils.readSettings(); - // Ignore Settings.toml diagnostics in the deprecate command - } catch (SettingsTomlException e) { - // Ignore 'Settings.toml' parsing errors and return empty Settings object - settings = Settings.from(); - } + settings = RepoUtils.readSettings(); + // Ignore Settings.toml diagnostics in the deprecate command + String packageValue = packageInfo; if (packageInfo.split(":").length != 2) { packageValue = packageInfo + ":*"; @@ -173,13 +168,13 @@ private void deprecateInCentral(String packageInfo) { settings.getProxy().password(), getAccessTokenOfCLI(settings), settings.getCentral().getConnectTimeout(), settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(), - settings.getCentral().getCallTimeout()); + settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries()); client.deprecatePackage(packageValue, deprecationMsg, JvmTarget.JAVA_17.code(), RepoUtils.getBallerinaVersion(), this.undoFlag); } catch (CentralClientException e) { String errorMessage = e.getMessage(); - if (null != errorMessage && !"".equals(errorMessage.trim())) { + if (null != errorMessage && !errorMessage.trim().isEmpty()) { // removing the error stack if (errorMessage.contains("\n\tat")) { errorMessage = errorMessage.substring(0, errorMessage.indexOf("\n\tat")); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/DocCommand.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/DocCommand.java index efd9d5e42019..6ae7ef87396b 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/DocCommand.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/DocCommand.java @@ -38,7 +38,6 @@ import java.io.IOException; import java.io.PrintStream; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; import static io.ballerina.cli.cmd.Constants.DOC_COMMAND; @@ -55,17 +54,17 @@ public class DocCommand implements BLauncherCmd { private final PrintStream errStream; private Path projectPath; private Path outputPath; - private boolean exitWhenFinish; + private final boolean exitWhenFinish; public DocCommand() { - this.projectPath = Paths.get(System.getProperty("user.dir")); + this.projectPath = Path.of(System.getProperty("user.dir")); this.outStream = System.out; this.errStream = System.err; this.exitWhenFinish = true; } DocCommand(PrintStream outStream, PrintStream errStream, boolean exitWhenFinish) { - this.projectPath = Paths.get(System.getProperty("user.dir")); + this.projectPath = Path.of(System.getProperty("user.dir")); this.outStream = outStream; this.errStream = errStream; this.exitWhenFinish = exitWhenFinish; @@ -73,7 +72,7 @@ public DocCommand() { } DocCommand(PrintStream outStream, PrintStream errStream, boolean exitWhenFinish, Path targetDir) { - this.projectPath = Paths.get(System.getProperty("user.dir")); + this.projectPath = Path.of(System.getProperty("user.dir")); this.outStream = outStream; this.errStream = errStream; this.exitWhenFinish = exitWhenFinish; @@ -110,6 +109,15 @@ public DocCommand() { "caching for source files", defaultValue = "false") private Boolean disableSyntaxTreeCaching; + @CommandLine.Option(names = "--show-dependency-diagnostics", description = "Show the diagnostics " + + "generated by the dependencies") + private Boolean showDependencyDiagnostics; + + @CommandLine.Option(names = "--optimize-dependency-compilation", hidden = true, + description = "experimental memory optimization for large projects") + private Boolean optimizeDependencyCompilation; + + @Override public void execute() { if (this.helpFlag) { String commandUsageInfo = BLauncherCmd.getCommandUsageInfo(DOC_COMMAND); @@ -117,11 +125,11 @@ public void execute() { return; } if (argList == null) { - this.projectPath = Paths.get(System.getProperty("user.dir")); + this.projectPath = Path.of(System.getProperty("user.dir")); } else { // Generate docs from a bala if (argList.get(0).endsWith(".bala")) { - this.projectPath = Paths.get(System.getProperty("user.dir")); + this.projectPath = Path.of(System.getProperty("user.dir")); Path balaPath = this.projectPath.resolve(argList.get(0)); ProjectEnvironmentBuilder defaultBuilder = ProjectEnvironmentBuilder.getDefaultBuilder(); defaultBuilder.addCompilationCacheFactory(TempDirCompilationCache::from); @@ -135,7 +143,7 @@ public void execute() { } return; } - this.projectPath = Paths.get(argList.get(0)); + this.projectPath = Path.of(argList.get(0)); } // combine docs if (this.combine) { @@ -178,7 +186,7 @@ public void execute() { // normalize paths this.projectPath = this.projectPath.normalize(); - this.outputPath = this.outputLoc != null ? Paths.get(this.outputLoc).toAbsolutePath() : null; + this.outputPath = this.outputLoc != null ? Path.of(this.outputLoc).toAbsolutePath() : null; TaskExecutor taskExecutor = new TaskExecutor.TaskBuilder() .addTask(new CreateTargetDirTask()) // create target directory. @@ -221,8 +229,9 @@ private BuildOptions constructBuildOptions() { .setOffline(offline) .setTestReport(false) .setObservabilityIncluded(false) - .disableSyntaxTreeCaching(disableSyntaxTreeCaching); - + .disableSyntaxTreeCaching(disableSyntaxTreeCaching) + .setShowDependencyDiagnostics(showDependencyDiagnostics) + .setOptimizeDependencyCompilation(optimizeDependencyCompilation); if (targetDir != null) { buildOptionsBuilder.targetDir(targetDir.toString()); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/GraphCommand.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/GraphCommand.java index 92b2412cc01c..310271fadfa0 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/GraphCommand.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/GraphCommand.java @@ -31,14 +31,11 @@ import io.ballerina.projects.directory.BuildProject; import io.ballerina.projects.directory.SingleFileProject; import io.ballerina.projects.util.ProjectConstants; -import io.ballerina.projects.util.ProjectUtils; -import org.ballerinalang.toml.exceptions.SettingsTomlException; import org.wso2.ballerinalang.util.RepoUtils; import picocli.CommandLine; import java.io.PrintStream; import java.nio.file.Path; -import java.nio.file.Paths; import static io.ballerina.cli.cmd.Constants.GRAPH_COMMAND; @@ -65,7 +62,7 @@ public class GraphCommand implements BLauncherCmd { private boolean helpFlag; @CommandLine.Option(names = {"--offline"}, description = "Print the dependency graph offline without downloading " + - "dependencies.", defaultValue = "false") + "dependencies.") private boolean offline; @CommandLine.Option(names = "--sticky", description = "stick to exact versions locked (if exists)", @@ -73,7 +70,7 @@ public class GraphCommand implements BLauncherCmd { private boolean sticky; public GraphCommand() { - this.projectPath = Paths.get(System.getProperty(ProjectConstants.USER_DIR)); + this.projectPath = Path.of(System.getProperty(ProjectConstants.USER_DIR)); this.outStream = System.out; this.errStream = System.err; this.exitWhenFinish = true; @@ -87,6 +84,7 @@ public GraphCommand() { this.offline = true; } + @Override public void execute() { if (this.helpFlag) { printHelpCommandInfo(); @@ -100,14 +98,8 @@ public void execute() { return; } - if (ProjectUtils.isProjectEmpty(this.project)) { - printErrorAndExit("package is empty. Please add at least one .bal file."); - return; - } - validateSettingsToml(); - TaskExecutor taskExecutor = new TaskExecutor.TaskBuilder() .addTask(new CleanTargetDirTask(true, false), isSingleFileProject()) .addTask(new RunBuildToolsTask(outStream), isSingleFileProject()) @@ -140,11 +132,7 @@ private void printErrorAndExit(String errorMessage) { } private void validateSettingsToml() { - try { - RepoUtils.readSettings(); - } catch (SettingsTomlException e) { - this.outStream.println("warning: " + e.getMessage()); - } + RepoUtils.readSettings(); } private void exitIfRequired() { diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/InitCommand.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/InitCommand.java index f63eaa07eeb1..313d299eac83 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/InitCommand.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/InitCommand.java @@ -27,7 +27,6 @@ import java.io.PrintStream; import java.nio.file.AccessDeniedException; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; import java.util.Optional; @@ -45,9 +44,9 @@ "release. Use `bal new .` instead") public class InitCommand implements BLauncherCmd { - private Path userDir; - private PrintStream errStream; - private boolean exitWhenFinish; + private final Path userDir; + private final PrintStream errStream; + private final boolean exitWhenFinish; @CommandLine.Option(names = {"--help", "-h"}, hidden = true) private boolean helpFlag; @@ -56,7 +55,7 @@ public class InitCommand implements BLauncherCmd { private List argList; public InitCommand() { - this.userDir = Paths.get(System.getProperty(ProjectConstants.USER_DIR)); + this.userDir = Path.of(System.getProperty(ProjectConstants.USER_DIR)); this.errStream = System.err; this.exitWhenFinish = true; CommandUtil.initJarFs(); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/NewCommand.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/NewCommand.java index e80ab33c868c..c1f77ec5ad6d 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/NewCommand.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/NewCommand.java @@ -32,7 +32,6 @@ import java.nio.file.AccessDeniedException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -51,8 +50,8 @@ @CommandLine.Command(name = NEW_COMMAND, description = "Create a new Ballerina package") public class NewCommand implements BLauncherCmd { - private PrintStream errStream; - private boolean exitWhenFinish; + private final PrintStream errStream; + private final boolean exitWhenFinish; Path homeCache = RepoUtils.createAndGetHomeReposPath(); @CommandLine.Parameters @@ -112,10 +111,10 @@ public void execute() { return; } - Path packagePath = Paths.get(argList.get(0)); - Path currentDir = Paths.get(System.getProperty(ProjectConstants.USER_DIR)); + Path packagePath = Path.of(argList.get(0)); + Path currentDir = Path.of(System.getProperty(ProjectConstants.USER_DIR)); if (!packagePath.isAbsolute()) { - packagePath = Paths.get(currentDir.toString(), packagePath.toString()).normalize(); + packagePath = Path.of(currentDir.toString(), packagePath.toString()).normalize(); } List filesInDir = new ArrayList<>(); @@ -156,7 +155,7 @@ public void execute() { // Check if package contains files/directories other than .bal files exist. String packageFiles = checkPackageFilesExists(packagePath); - if (!packageFiles.equals("") && !template.equals(DEFAULT_TEMPLATE)) { + if (!packageFiles.isEmpty() && !template.equals(DEFAULT_TEMPLATE)) { CommandUtil.printError(errStream, "existing " + packageFiles.substring(0, packageFiles.length() - 2) + " file/directory(s) were found. " + @@ -257,7 +256,7 @@ public void execute() { // create package with inbuilt template if (Files.exists((packagePath))) { String existingFiles = CommandUtil.checkTemplateFilesExists(template, packagePath); - if (!existingFiles.equals("")) { + if (!existingFiles.isEmpty()) { CommandUtil.printError(errStream, "existing " + existingFiles.substring(0, existingFiles.length() - 2) + " file/directory(s) were found. " + @@ -301,8 +300,8 @@ public void execute() { } if (Files.exists(packagePath)) { // If the provided path argument is relative, print it as it is - if (!Paths.get(argList.get(0)).isAbsolute()) { - packagePath = Paths.get(argList.get(0)); + if (!Path.of(argList.get(0)).isAbsolute()) { + packagePath = Path.of(argList.get(0)); } errStream.println("Created new package '" + packageName + "' at " + packagePath + "."); } diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/PackCommand.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/PackCommand.java index 5fc2a1b755b8..fd064c8d1dfe 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/PackCommand.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/PackCommand.java @@ -15,16 +15,13 @@ import io.ballerina.projects.ProjectException; import io.ballerina.projects.directory.BuildProject; import io.ballerina.projects.util.ProjectConstants; -import io.ballerina.projects.util.ProjectUtils; import io.ballerina.toml.semantic.TomlType; import io.ballerina.toml.semantic.ast.TomlTableNode; -import org.ballerinalang.toml.exceptions.SettingsTomlException; import org.wso2.ballerinalang.util.RepoUtils; import picocli.CommandLine; import java.io.PrintStream; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; @@ -90,8 +87,16 @@ public class PackCommand implements BLauncherCmd { "caching for source files", defaultValue = "false") private Boolean disableSyntaxTreeCaching; + @CommandLine.Option(names = "--show-dependency-diagnostics", description = "Show the diagnostics " + + "generated by the dependencies") + private Boolean showDependencyDiagnostics; + + @CommandLine.Option(names = "--optimize-dependency-compilation", hidden = true, + description = "experimental memory optimization for large projects") + private Boolean optimizeDependencyCompilation; + public PackCommand() { - this.projectPath = Paths.get(System.getProperty(ProjectConstants.USER_DIR)); + this.projectPath = Path.of(System.getProperty(ProjectConstants.USER_DIR)); this.outStream = System.out; this.errStream = System.err; this.exitWhenFinish = true; @@ -108,6 +113,17 @@ public PackCommand() { this.offline = true; } + PackCommand(Path projectPath, PrintStream outStream, PrintStream errStream, boolean exitWhenFinish, + boolean skipCopyLibsFromDist, Boolean optimizeDependencyCompilation) { + this.projectPath = projectPath; + this.outStream = outStream; + this.errStream = errStream; + this.exitWhenFinish = exitWhenFinish; + this.skipCopyLibsFromDist = skipCopyLibsFromDist; + this.optimizeDependencyCompilation = optimizeDependencyCompilation; + this.offline = true; + } + PackCommand(Path projectPath, PrintStream outStream, PrintStream errStream, boolean exitWhenFinish, boolean skipCopyLibsFromDist, Path targetDir) { this.projectPath = projectPath; @@ -160,15 +176,6 @@ public void execute() { return; } - // If project is empty - if (ProjectUtils.isProjectEmpty(project) && project.currentPackage().compilerPluginToml().isEmpty() && - project.currentPackage().balToolToml().isEmpty()) { - CommandUtil.printError(this.errStream, "package is empty. Please add at least one .bal file.", null, - false); - CommandUtil.exitError(this.exitWhenFinish); - return; - } - // Check `[package]` section is available when compile if (project.currentPackage().ballerinaToml().get().tomlDocument().toml().getTable("package") .isEmpty()) { @@ -237,11 +244,7 @@ public void execute() { } // Validate Settings.toml file - try { - RepoUtils.readSettings(); - } catch (SettingsTomlException e) { - this.outStream.println("warning: " + e.getMessage()); - } + RepoUtils.readSettings(); // Check package files are modified after last build boolean isPackageModified = isProjectUpdated(project); @@ -274,7 +277,9 @@ private BuildOptions constructBuildOptions() { .setSticky(sticky) .setConfigSchemaGen(configSchemaGen) .setEnableCache(enableCache) - .disableSyntaxTreeCaching(disableSyntaxTreeCaching); + .disableSyntaxTreeCaching(disableSyntaxTreeCaching) + .setShowDependencyDiagnostics(showDependencyDiagnostics) + .setOptimizeDependencyCompilation(optimizeDependencyCompilation); if (targetDir != null) { buildOptionsBuilder.targetDir(targetDir.toString()); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/ProfileCommand.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/ProfileCommand.java index da76ac2defc7..bcf270755634 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/ProfileCommand.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/ProfileCommand.java @@ -35,12 +35,10 @@ import io.ballerina.projects.directory.BuildProject; import io.ballerina.projects.directory.SingleFileProject; import io.ballerina.projects.util.ProjectConstants; -import io.ballerina.projects.util.ProjectUtils; import picocli.CommandLine; import java.io.PrintStream; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; @@ -88,10 +86,18 @@ public class ProfileCommand implements BLauncherCmd { "caching for source files", defaultValue = "false") private Boolean disableSyntaxTreeCaching; + @CommandLine.Option(names = "--show-dependency-diagnostics", description = "Show the diagnostics " + + "generated by the dependencies") + private Boolean showDependencyDiagnostics; + + @CommandLine.Option(names = "--optimize-dependency-compilation", hidden = true, + description = "experimental memory optimization for large projects") + private Boolean optimizeDependencyCompilation; + private static final String PROFILE_CMD = "bal profile [--debug ] []\n "; public ProfileCommand() { - this.projectPath = Paths.get(System.getProperty(ProjectConstants.USER_DIR)); + this.projectPath = Path.of(System.getProperty(ProjectConstants.USER_DIR)); this.outStream = System.err; this.errStream = System.err; } @@ -104,6 +110,7 @@ public ProfileCommand() { this.offline = true; } + @Override public void execute() { if (this.helpFlag) { printCommandUsageInfo(); @@ -118,12 +125,6 @@ public void execute() { CommandUtil.exitError(this.exitWhenFinish); return; } - if (ProjectUtils.isProjectEmpty(project)) { - CommandUtil.printError(this.errStream, "package is empty. Please add at least one .bal file.", - null, false); - CommandUtil.exitError(this.exitWhenFinish); - return; - } boolean isPackageModified = isProjectUpdated(project); TaskExecutor taskExecutor = createTaskExecutor(isPackageModified, args, buildOptions, project.kind() == ProjectKind.SINGLE_FILE_PROJECT); @@ -152,7 +153,7 @@ private String[] getArgumentsFromArgList() { String[] args = new String[0]; if (!argList.isEmpty()) { if (!argList.get(0).equals("--")) { // project path provided - this.projectPath = Paths.get(argList.get(0)); + this.projectPath = Path.of(argList.get(0)); if (argList.size() > 2 && argList.get(1).equals("--")) { // args to main provided args = argList.subList(2, argList.size()).toArray(new String[0]); } @@ -199,7 +200,7 @@ private TaskExecutor createTaskExecutor(boolean isPackageModified, String[] args .addTask(new ResolveMavenDependenciesTask(outStream)) .addTask(new CompileTask(outStream, errStream, false, false, isPackageModified, buildOptions.enableCache())) - .addTask(new CreateExecutableTask(outStream, null), false) + .addTask(new CreateExecutableTask(outStream, null, null, false), false) .addTask(new DumpBuildTimeTask(outStream), false) .addTask(new RunProfilerTask(errStream), false).build(); } @@ -232,7 +233,9 @@ private BuildOptions constructBuildOptions() { .setSkipTests(true) .setTestReport(false) .setConfigSchemaGen(configSchemaGen) - .disableSyntaxTreeCaching(disableSyntaxTreeCaching); + .disableSyntaxTreeCaching(disableSyntaxTreeCaching) + .setShowDependencyDiagnostics(showDependencyDiagnostics) + .setOptimizeDependencyCompilation(optimizeDependencyCompilation); if (targetDir != null) { buildOptionsBuilder.targetDir(targetDir.toString()); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/PullCommand.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/PullCommand.java index 827663c6bcaf..07be37fcec5f 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/PullCommand.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/PullCommand.java @@ -21,6 +21,7 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; import io.ballerina.cli.BLauncherCmd; +import io.ballerina.projects.BuildOptions; import io.ballerina.projects.JvmTarget; import io.ballerina.projects.ProjectException; import io.ballerina.projects.SemanticVersion; @@ -29,13 +30,13 @@ import io.ballerina.projects.internal.model.Repository; import io.ballerina.projects.util.ProjectConstants; import io.ballerina.projects.util.ProjectUtils; +import org.apache.commons.io.FileUtils; import org.ballerinalang.central.client.CentralAPIClient; import org.ballerinalang.central.client.CentralClientConstants; import org.ballerinalang.central.client.exceptions.CentralClientException; import org.ballerinalang.central.client.exceptions.PackageAlreadyExistsException; import org.ballerinalang.maven.bala.client.MavenResolverClient; import org.ballerinalang.maven.bala.client.MavenResolverClientException; -import org.ballerinalang.toml.exceptions.SettingsTomlException; import org.wso2.ballerinalang.compiler.util.Names; import org.wso2.ballerinalang.util.RepoUtils; import picocli.CommandLine; @@ -53,6 +54,7 @@ import static io.ballerina.cli.cmd.Constants.PULL_COMMAND; import static io.ballerina.cli.launcher.LauncherUtils.createLauncherException; import static io.ballerina.projects.util.ProjectConstants.BALA_EXTENSION; +import static io.ballerina.projects.util.ProjectConstants.LOCAL_REPOSITORY_NAME; import static io.ballerina.projects.util.ProjectConstants.PLATFORM; import static io.ballerina.projects.util.ProjectUtils.getAccessTokenOfCLI; import static io.ballerina.projects.util.ProjectUtils.initializeProxy; @@ -72,8 +74,9 @@ public class PullCommand implements BLauncherCmd { private static final String USAGE_TEXT = "bal pull {/ | /:}"; - private PrintStream errStream; - private boolean exitWhenFinish; + private final PrintStream outStream; + private final PrintStream errStream; + private final boolean exitWhenFinish; @CommandLine.Parameters private List argList; @@ -87,14 +90,23 @@ public class PullCommand implements BLauncherCmd { @CommandLine.Option(names = "--repository") private String repositoryName; + @CommandLine.Option(names = "--sticky", hidden = true, defaultValue = "true") + private boolean sticky; + + @CommandLine.Option(names = "--offline", hidden = true) + private boolean offline; + public PullCommand() { + this.outStream = System.out; this.errStream = System.err; this.exitWhenFinish = true; } public PullCommand(PrintStream errStream, boolean exitWhenFinish) { + this.outStream = errStream; this.errStream = errStream; this.exitWhenFinish = exitWhenFinish; + this.repositoryName = null; } @Override @@ -132,7 +144,7 @@ public void execute() { // Get org name String[] moduleInfo = resourceName.split("/"); if (moduleInfo.length != 2) { - CommandUtil.printError(errStream, "invalid package name. Provide the package name with the organization.", + CommandUtil.printError(errStream, "invalid package. Provide the package name with the organization.", USAGE_TEXT, false); CommandUtil.exitError(this.exitWhenFinish); return; @@ -149,7 +161,7 @@ public void execute() { packageName = moduleNameAndVersion; version = Names.EMPTY.getValue(); } else { - CommandUtil.printError(errStream, "invalid package name. Provide the package name with the organization.", + CommandUtil.printError(errStream, "invalid package. Provide the package name with the organization.", USAGE_TEXT, false); CommandUtil.exitError(this.exitWhenFinish); return; @@ -180,19 +192,79 @@ public void execute() { } Settings settings; + settings = RepoUtils.readSettings(); + + if (repositoryName == null) { + repositoryName = ProjectConstants.CENTRAL_REPOSITORY_CACHE_NAME; + version = pullFromCentral(settings, orgName, packageName, version); + } else if (!LOCAL_REPOSITORY_NAME.equals(repositoryName)) { + pullFromMavenRepo(settings, orgName, packageName, version); + } + + if (!resolveDependencies(orgName, packageName, version)) { + CommandUtil.exitError(this.exitWhenFinish); + return; + } + + if (this.exitWhenFinish) { + Runtime.getRuntime().exit(0); + } + + } + + private String pullFromCentral(Settings settings, String orgName, String packageName, String version) { + Path packagePathInBalaCache = ProjectUtils.createAndGetHomeReposPath() + .resolve(ProjectConstants.REPOSITORIES_DIR).resolve(ProjectConstants.CENTRAL_REPOSITORY_CACHE_NAME) + .resolve(ProjectConstants.BALA_DIR_NAME) + .resolve(orgName).resolve(packageName); + + if (!version.equals(Names.EMPTY.getValue()) && Files.exists(packagePathInBalaCache.resolve(version))) { + outStream.println("Package already exists.\n"); + } + // create directory path in bala cache try { - settings = RepoUtils.readSettings(); - } catch (SettingsTomlException e) { - settings = Settings.from(); + createDirectories(packagePathInBalaCache); + } catch (IOException e) { + CommandUtil.exitError(this.exitWhenFinish); + throw createLauncherException( + "unexpected error occurred while creating package repository in bala cache: " + e.getMessage()); + } + + CommandUtil.setPrintStream(errStream); + String supportedPlatform = Arrays.stream(JvmTarget.values()) + .map(JvmTarget::code) + .collect(Collectors.joining(",")); + CentralAPIClient client; + try { + client = new CentralAPIClient(RepoUtils.getRemoteRepoURL(), + initializeProxy(settings.getProxy()), settings.getProxy().username(), + settings.getProxy().password(), getAccessTokenOfCLI(settings), + settings.getCentral().getConnectTimeout(), + settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(), + settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries()); + client.pullPackage(orgName, packageName, version, packagePathInBalaCache, supportedPlatform, + RepoUtils.getBallerinaVersion(), false); + if (version.equals(Names.EMPTY.getValue())) { + List versions = client.getPackageVersions(orgName, packageName, supportedPlatform, + RepoUtils.getBallerinaVersion()); + version = CommandUtil.getLatestVersion(versions); + } + } catch (PackageAlreadyExistsException e) { + outStream.println("Package already exists.\n"); + version = e.version(); + } catch (CentralClientException e) { + errStream.println("package not found: " + orgName + "/" + packageName); + CommandUtil.exitError(this.exitWhenFinish); } + return version; + } + private void pullFromMavenRepo(Settings settings, String orgName, String packageName, String version) { Repository targetRepository = null; - if (repositoryName != null) { - for (Repository repository : settings.getRepositories()) { - if (repositoryName.equals(repository.id())) { - targetRepository = repository; - break; - } + for (Repository repository : settings.getRepositories()) { + if (repositoryName.equals(repository.id())) { + targetRepository = repository; + break; } } @@ -218,7 +290,8 @@ public void execute() { Path mavenBalaCachePath = RepoUtils.createAndGetHomeReposPath() .resolve(ProjectConstants.REPOSITORIES_DIR) .resolve(targetRepository.id()) - .resolve(ProjectConstants.BALA_DIR_NAME); + .resolve(ProjectConstants.BALA_DIR_NAME) + .resolve(orgName).resolve(packageName).resolve(version); try { Path tmpDownloadDirectory = Files.createTempDirectory("ballerina-" + System.nanoTime()); @@ -233,10 +306,8 @@ public void execute() { try (BufferedReader bufferedReader = Files.newBufferedReader(packageJsonPath, StandardCharsets.UTF_8)) { JsonObject resultObj = new Gson().fromJson(bufferedReader, JsonObject.class); String platform = resultObj.get(PLATFORM).getAsString(); - Path actualBalaPath = mavenBalaCachePath.resolve(orgName).resolve(packageName) - .resolve(version).resolve(platform); - org.apache.commons.io.FileUtils.copyDirectory(temporaryExtractionPath.toFile(), - actualBalaPath.toFile()); + Path actualBalaPath = mavenBalaCachePath.resolve(platform); + FileUtils.copyDirectory(temporaryExtractionPath.toFile(), actualBalaPath.toFile()); } } catch (MavenResolverClientException e) { errStream.println("unexpected error occurred while pulling package:" + e.getMessage()); @@ -247,56 +318,24 @@ public void execute() { } PrintStream out = System.out; out.println("Successfully pulled the package from the custom repository."); - return; - } - - Path packagePathInBalaCache = ProjectUtils.createAndGetHomeReposPath() - .resolve(ProjectConstants.REPOSITORIES_DIR).resolve(ProjectConstants.CENTRAL_REPOSITORY_CACHE_NAME) - .resolve(ProjectConstants.BALA_DIR_NAME) - .resolve(orgName).resolve(packageName); - // create directory path in bala cache - try { - createDirectories(packagePathInBalaCache); - } catch (IOException e) { - CommandUtil.exitError(this.exitWhenFinish); - throw createLauncherException( - "unexpected error occurred while creating package repository in bala cache: " + e.getMessage()); } + } + private boolean resolveDependencies(String orgName, String packageName, String version) { CommandUtil.setPrintStream(errStream); - String supportedPlatform = Arrays.stream(JvmTarget.values()) - .map(JvmTarget::code) - .collect(Collectors.joining(",")); try { - CentralAPIClient client = new CentralAPIClient(RepoUtils.getRemoteRepoURL(), - initializeProxy(settings.getProxy()), settings.getProxy().username(), - settings.getProxy().password(), getAccessTokenOfCLI(settings), - settings.getCentral().getConnectTimeout(), - settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(), - settings.getCentral().getCallTimeout()); - client.pullPackage(orgName, packageName, version, packagePathInBalaCache, supportedPlatform, - RepoUtils.getBallerinaVersion(), false); - if (version.equals(Names.EMPTY.getValue())) { - List versions = client.getPackageVersions(orgName, packageName, supportedPlatform, - RepoUtils.getBallerinaVersion()); - version = CommandUtil.getLatestVersion(versions); - } - boolean hasCompilationErrors = CommandUtil.pullDependencyPackages(orgName, packageName, version); + BuildOptions buildOptions = BuildOptions.builder().setSticky(sticky).setOffline(offline).build(); + boolean hasCompilationErrors = CommandUtil.pullDependencyPackages( + orgName, packageName, version, buildOptions, repositoryName); if (hasCompilationErrors) { CommandUtil.printError(this.errStream, "compilation contains errors", null, false); - CommandUtil.exitError(this.exitWhenFinish); - return; + return false; } - } catch (PackageAlreadyExistsException e) { - errStream.println(e.getMessage()); - CommandUtil.exitError(this.exitWhenFinish); - } catch (CentralClientException e) { - errStream.println("package not found: " + orgName + "/" + packageName); - CommandUtil.exitError(this.exitWhenFinish); - } - if (this.exitWhenFinish) { - Runtime.getRuntime().exit(0); + } catch (ProjectException e) { + CommandUtil.printError(this.errStream, + "error occurred while resolving dependencies, reason: " + e.getMessage(), null, false); } + return true; } @Override diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/PushCommand.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/PushCommand.java index 3ae1b62eaaba..b0bb908418c2 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/PushCommand.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/PushCommand.java @@ -42,7 +42,6 @@ import org.ballerinalang.central.client.exceptions.NoPackageException; import org.ballerinalang.maven.bala.client.MavenResolverClient; import org.ballerinalang.maven.bala.client.MavenResolverClientException; -import org.ballerinalang.toml.exceptions.SettingsTomlException; import org.wso2.ballerinalang.util.RepoUtils; import picocli.CommandLine; @@ -54,7 +53,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.Arrays; import java.util.Optional; @@ -100,13 +98,13 @@ public class PushCommand implements BLauncherCmd { @CommandLine.Option(names = {"--skip-source-check"}, description = "skip checking if source has changed") private boolean skipSourceCheck; - private Path userDir; - private PrintStream errStream; - private PrintStream outStream; - private boolean exitWhenFinish; + private final Path userDir; + private final PrintStream errStream; + private final PrintStream outStream; + private final boolean exitWhenFinish; public PushCommand() { - this.userDir = Paths.get(System.getProperty(ProjectConstants.USER_DIR)); + this.userDir = Path.of(System.getProperty(ProjectConstants.USER_DIR)); this.errStream = System.err; this.outStream = System.out; this.exitWhenFinish = true; @@ -234,7 +232,7 @@ public void execute() { settings.getProxy().password(), getAccessTokenOfCLI(settings), settings.getCentral().getConnectTimeout(), settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(), - settings.getCentral().getCallTimeout()); + settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries()); if (balaPath == null) { pushPackage(project, client); } else { @@ -249,7 +247,7 @@ public void execute() { pushBalaToRemote(balaPath, client); } } - } catch (ProjectException | CentralClientException | SettingsTomlException e) { + } catch (ProjectException | CentralClientException e) { CommandUtil.printError(this.errStream, e.getMessage(), null, false); CommandUtil.exitError(this.exitWhenFinish); return; @@ -484,25 +482,20 @@ private void pushBalaToRemote(Path balaPath, CentralAPIClient client) { Path ballerinaHomePath = RepoUtils.createAndGetHomeReposPath(); Path settingsTomlFilePath = ballerinaHomePath.resolve(SETTINGS_FILE_NAME); - try { - authenticate(errStream, getBallerinaCentralCliTokenUrl(), settingsTomlFilePath, client); - } catch (SettingsTomlException e) { - CommandUtil.printError(this.errStream, e.getMessage(), null, false); - return; - } + authenticate(errStream, getBallerinaCentralCliTokenUrl(), settingsTomlFilePath, client); try { client.pushPackage(balaPath, org, name, version, JvmTarget.JAVA_17.code(), RepoUtils.getBallerinaVersion()); } catch (CentralClientException e) { String errorMessage = e.getMessage(); - if (null != errorMessage && !"".equals(errorMessage.trim())) { + if (null != errorMessage && !errorMessage.trim().isEmpty()) { // removing the error stack if (errorMessage.contains("\n\tat")) { errorMessage = errorMessage.substring(0, errorMessage.indexOf("\n\tat")); } - errorMessage = errorMessage.replaceAll("error: ", ""); + errorMessage = errorMessage.replace("error: ", ""); // when unauthorized access token for organization is given if (errorMessage.contains("subject claims missing in the user info repsonse")) { diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/RunCommand.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/RunCommand.java index debd61345784..14010c596033 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/RunCommand.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/RunCommand.java @@ -22,30 +22,36 @@ import io.ballerina.cli.TaskExecutor; import io.ballerina.cli.task.CleanTargetDirTask; import io.ballerina.cli.task.CompileTask; +import io.ballerina.cli.task.CreateExecutableTask; import io.ballerina.cli.task.DumpBuildTimeTask; import io.ballerina.cli.task.ResolveMavenDependenciesTask; import io.ballerina.cli.task.RunBuildToolsTask; import io.ballerina.cli.task.RunExecutableTask; import io.ballerina.cli.utils.BuildTime; import io.ballerina.cli.utils.FileUtils; +import io.ballerina.cli.utils.ProjectWatcher; import io.ballerina.projects.BuildOptions; import io.ballerina.projects.Project; import io.ballerina.projects.ProjectException; +import io.ballerina.projects.ProjectKind; import io.ballerina.projects.directory.BuildProject; import io.ballerina.projects.directory.SingleFileProject; +import io.ballerina.projects.internal.model.Target; import io.ballerina.projects.util.ProjectConstants; import io.ballerina.projects.util.ProjectUtils; import picocli.CommandLine; +import java.io.IOException; import java.io.PrintStream; import java.nio.file.FileSystems; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import static io.ballerina.cli.cmd.Constants.RUN_COMMAND; +import static io.ballerina.cli.launcher.LauncherUtils.createLauncherException; import static io.ballerina.projects.util.ProjectUtils.isProjectUpdated; import static io.ballerina.runtime.api.constants.RuntimeConstants.SYSTEM_PROP_BAL_DEBUG; @@ -61,6 +67,8 @@ public class RunCommand implements BLauncherCmd { private final PrintStream errStream; private Path projectPath; private boolean exitWhenFinish; + RunExecutableTask runExecutableTask; + Project project; private static final PathMatcher JAR_EXTENSION_MATCHER = FileSystems.getDefault().getPathMatcher("glob:**.jar"); @@ -78,6 +86,8 @@ public class RunCommand implements BLauncherCmd { @CommandLine.Option(names = "--debug", hidden = true) private String debugPort; + @CommandLine.Option(names = "--watch", description = "watch for file changes and automatically re-run the project") + private boolean watch; @CommandLine.Option(names = "--dump-bir", hidden = true) private boolean dumpBIR; @@ -116,6 +126,14 @@ public class RunCommand implements BLauncherCmd { @CommandLine.Option(names = "--dump-build-time", description = "calculate and dump build time", hidden = true) private Boolean dumpBuildTime; + @CommandLine.Option(names = "--show-dependency-diagnostics", description = "Show the diagnostics " + + "generated by the dependencies") + private Boolean showDependencyDiagnostics; + + @CommandLine.Option(names = "--optimize-dependency-compilation", hidden = true, + description = "experimental memory optimization for large projects") + private Boolean optimizeDependencyCompilation; + private static final String runCmd = """ bal run [--debug ] \s @@ -124,7 +142,7 @@ public class RunCommand implements BLauncherCmd { \s"""; public RunCommand() { - this.projectPath = Paths.get(System.getProperty(ProjectConstants.USER_DIR)); + this.projectPath = Path.of(System.getProperty(ProjectConstants.USER_DIR)); this.outStream = System.err; this.errStream = System.err; } @@ -136,6 +154,14 @@ public RunCommand() { this.errStream = outStream; this.offline = true; } + RunCommand(Path projectPath, PrintStream outStream, boolean exitWhenFinish, Boolean optimizeDependencyCompilation) { + this.projectPath = projectPath; + this.exitWhenFinish = exitWhenFinish; + this.outStream = outStream; + this.errStream = outStream; + this.optimizeDependencyCompilation = optimizeDependencyCompilation; + this.offline = true; + } RunCommand(Path projectPath, PrintStream outStream, boolean exitWhenFinish, Path targetDir) { this.projectPath = projectPath; @@ -146,6 +172,7 @@ public RunCommand() { this.offline = true; } + @Override public void execute() { long start = 0; if (this.helpFlag) { @@ -163,7 +190,7 @@ public void execute() { String[] args = new String[0]; if (!argList.isEmpty()) { if (!argList.get(0).equals("--")) { // project path provided - this.projectPath = Paths.get(argList.get(0)); + this.projectPath = Path.of(argList.get(0)); if (RunCommand.JAR_EXTENSION_MATCHER.matches(this.projectPath)) { CommandUtil.printError(this.errStream, "unsupported option(s) provided for jar execution", runCmd, true); @@ -190,8 +217,22 @@ public void execute() { sticky = false; } + if (this.watch) { + try { + ProjectWatcher projectWatcher = new ProjectWatcher( + this, Path.of(this.projectPath.toString()), outStream); + projectWatcher.watch(); + } catch (IOException e) { + throw createLauncherException("unable to watch the project:" + e.getMessage()); + } catch (ProjectException e) { + CommandUtil.printError(this.errStream, e.getMessage(), runCmd, false); + CommandUtil.exitError(this.exitWhenFinish); + } + return; + } + + // load project - Project project; BuildOptions buildOptions = constructBuildOptions(); boolean isSingleFileBuild = false; @@ -228,11 +269,18 @@ public void execute() { } } - // If project is empty - if (ProjectUtils.isProjectEmpty(project)) { - CommandUtil.printError(this.errStream, "package is empty. Please add at least one .bal file.", null, false); - CommandUtil.exitError(this.exitWhenFinish); - return; + Target target; + try { + if (project.kind().equals(ProjectKind.BUILD_PROJECT)) { + target = new Target(project.targetDir()); + } else { + target = new Target(Files.createTempDirectory("ballerina-cache" + System.nanoTime())); + target.setOutputPath(target.getBinPath()); + } + } catch (IOException e) { + throw createLauncherException("unable to resolve the target path:" + e.getMessage()); + } catch (ProjectException e) { + throw createLauncherException("unable to create the executable:" + e.getMessage()); } // Check package files are modified after last build @@ -248,7 +296,8 @@ public void execute() { .addTask(new CompileTask(outStream, errStream, false, false, isPackageModified, buildOptions.enableCache())) // .addTask(new CopyResourcesTask(), isSingleFileBuild) - .addTask(new RunExecutableTask(args, outStream, errStream)) + .addTask(new CreateExecutableTask(outStream, null, target, true)) + .addTask(runExecutableTask = new RunExecutableTask(args, outStream, errStream, target)) .addTask(new DumpBuildTimeTask(outStream), !project.buildOptions().dumpBuildTime()) .build(); taskExecutor.executeTasks(project); @@ -277,6 +326,16 @@ public void printUsage(StringBuilder out) { public void setParentCmdParser(CommandLine parentCmdParser) { } + public void unsetWatch() { + this.watch = false; + } + + public void killProcess() { + if (runExecutableTask != null) { + runExecutableTask.killProcess(); + } + } + private BuildOptions constructBuildOptions() { BuildOptions.BuildOptionsBuilder buildOptionsBuilder = BuildOptions.builder(); @@ -292,7 +351,9 @@ private BuildOptions constructBuildOptions() { .setDumpRawGraphs(dumpRawGraphs) .setConfigSchemaGen(configSchemaGen) .disableSyntaxTreeCaching(disableSyntaxTreeCaching) - .setDumpBuildTime(dumpBuildTime); + .setDumpBuildTime(dumpBuildTime) + .setShowDependencyDiagnostics(showDependencyDiagnostics) + .setOptimizeDependencyCompilation(optimizeDependencyCompilation); if (targetDir != null) { buildOptionsBuilder.targetDir(targetDir.toString()); @@ -300,4 +361,8 @@ private BuildOptions constructBuildOptions() { return buildOptionsBuilder.build(); } + + public boolean containsService() { + return project == null || ProjectUtils.containsDefaultModuleService(project.currentPackage()); + } } diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/SearchCommand.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/SearchCommand.java index f4474f6bd66d..353946d66119 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/SearchCommand.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/SearchCommand.java @@ -24,7 +24,6 @@ import org.ballerinalang.central.client.CentralAPIClient; import org.ballerinalang.central.client.exceptions.CentralClientException; import org.ballerinalang.central.client.model.PackageSearchResult; -import org.ballerinalang.toml.exceptions.SettingsTomlException; import org.wso2.ballerinalang.util.RepoUtils; import picocli.CommandLine; @@ -47,9 +46,9 @@ @CommandLine.Command(name = SEARCH_COMMAND, description = "Search Ballerina Central for packages") public class SearchCommand implements BLauncherCmd { - private PrintStream outStream; - private PrintStream errStream; - private boolean exitWhenFinish; + private final PrintStream outStream; + private final PrintStream errStream; + private final boolean exitWhenFinish; @CommandLine.Parameters private List argList; @@ -133,13 +132,9 @@ public void setParentCmdParser(CommandLine parentCmdParser) { private void searchInCentral(String query) { try { Settings settings; - try { - settings = RepoUtils.readSettings(); - // Ignore Settings.toml diagnostics in the search command - } catch (SettingsTomlException e) { - // Ignore 'Settings.toml' parsing errors and return empty Settings object - settings = Settings.from(); - } + settings = RepoUtils.readSettings(); + // Ignore Settings.toml diagnostics in the search command + CentralAPIClient client = new CentralAPIClient(RepoUtils.getRemoteRepoURL(), initializeProxy(settings.getProxy()), settings.getProxy().username(), @@ -148,7 +143,8 @@ private void searchInCentral(String query) { settings.getCentral().getConnectTimeout(), settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(), - settings.getCentral().getCallTimeout()); + settings.getCentral().getCallTimeout(), + settings.getCentral().getMaxRetries()); boolean foundSearch = false; String supportedPlatform = Arrays.stream(JvmTarget.values()) .map(target -> target.code()) @@ -164,7 +160,7 @@ private void searchInCentral(String query) { } } catch (CentralClientException e) { String errorMessage = e.getMessage(); - if (null != errorMessage && !"".equals(errorMessage.trim())) { + if (null != errorMessage && !errorMessage.trim().isEmpty()) { // removing the error stack if (errorMessage.contains("\n\tat")) { errorMessage = errorMessage.substring(0, errorMessage.indexOf("\n\tat")); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/ShellCommand.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/ShellCommand.java index 409d8f7b0e83..b1e3c51a32a6 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/ShellCommand.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/ShellCommand.java @@ -34,7 +34,7 @@ */ @CommandLine.Command(name = SHELL_COMMAND, description = "Run Ballerina interactive REPL") public class ShellCommand implements BLauncherCmd { - private PrintStream errStream; + private final PrintStream errStream; @CommandLine.Option(names = {"--help", "-h", "?"}, hidden = true) private boolean helpFlag; @@ -78,7 +78,7 @@ public void execute() { BShellConfiguration configuration = builder.build(); ReplShellApplication.execute(configuration); } catch (Exception e) { - errStream.println("something went wrong while executing REPL: " + e.toString()); + errStream.println("something went wrong while executing REPL: " + e); } } diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/TestCommand.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/TestCommand.java index c837653ee6a8..8240f19b876b 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/TestCommand.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/TestCommand.java @@ -19,8 +19,10 @@ import io.ballerina.cli.BLauncherCmd; import io.ballerina.cli.TaskExecutor; +import io.ballerina.cli.task.CleanTargetBinTestsDirTask; import io.ballerina.cli.task.CleanTargetCacheDirTask; import io.ballerina.cli.task.CompileTask; +import io.ballerina.cli.task.CreateTestExecutableTask; import io.ballerina.cli.task.DumpBuildTimeTask; import io.ballerina.cli.task.ResolveMavenDependenciesTask; import io.ballerina.cli.task.RunBuildToolsTask; @@ -35,12 +37,10 @@ import io.ballerina.projects.directory.BuildProject; import io.ballerina.projects.directory.SingleFileProject; import io.ballerina.projects.util.ProjectConstants; -import io.ballerina.projects.util.ProjectUtils; import picocli.CommandLine; import java.io.PrintStream; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -65,7 +65,7 @@ public class TestCommand implements BLauncherCmd { private final boolean exitWhenFinish; public TestCommand() { - this.projectPath = Paths.get(System.getProperty(ProjectConstants.USER_DIR)); + this.projectPath = Path.of(System.getProperty(ProjectConstants.USER_DIR)); this.outStream = System.out; this.errStream = System.err; this.exitWhenFinish = true; @@ -79,6 +79,15 @@ public TestCommand() { this.offline = true; } + TestCommand(Path projectPath, boolean exitWhenFinish, Boolean optimizeDependencyCompilation) { + this.projectPath = projectPath; + this.optimizeDependencyCompilation = optimizeDependencyCompilation; + this.outStream = System.out; + this.errStream = System.err; + this.exitWhenFinish = exitWhenFinish; + this.offline = true; + } + TestCommand(Path projectPath, PrintStream outStream, PrintStream errStream, boolean exitWhenFinish) { this.projectPath = projectPath; this.outStream = outStream; @@ -88,7 +97,8 @@ public TestCommand() { } TestCommand(Path projectPath, PrintStream outStream, PrintStream errStream, boolean exitWhenFinish, - Boolean testReport, Boolean coverage, String coverageFormat) { + Boolean testReport, Boolean coverage, String coverageFormat, + Boolean optimizeDependencyCompilation) { this.projectPath = projectPath; this.outStream = outStream; this.errStream = errStream; @@ -96,6 +106,7 @@ public TestCommand() { this.testReport = testReport; this.coverage = coverage; this.coverageFormat = coverageFormat; + this.optimizeDependencyCompilation = optimizeDependencyCompilation; this.offline = true; } @@ -201,10 +212,21 @@ public TestCommand() { "generation") private String graalVMBuildOptions; + @CommandLine.Option(names = "--show-dependency-diagnostics", description = "Show the diagnostics " + + "generated by the dependencies") + private Boolean showDependencyDiagnostics; + + @CommandLine.Option(names = "--cloud", description = "Enable cloud artifact generation") + private String cloud; + + @CommandLine.Option(names = "--optimize-dependency-compilation", hidden = true, + description = "experimental memory optimization for large projects") + private Boolean optimizeDependencyCompilation; private static final String testCmd = "bal test [--OPTIONS]\n" + " [ | ] [(-Ckey=value)...]"; + @Override public void execute() { long start = 0; if (this.helpFlag) { @@ -216,7 +238,7 @@ public void execute() { String[] cliArgs = new String[0]; if (!argList.isEmpty()) { if (!argList.get(0).matches(ProjectConstants.CONFIG_ARGS_PATTERN)) { - this.projectPath = Paths.get(argList.get(0)); + this.projectPath = Path.of(argList.get(0)); if (argList.size() > 1) { cliArgs = argList.subList(1, argList.size()).toArray(new String[0]); } @@ -280,13 +302,6 @@ public void execute() { } } - // If project is empty - if (ProjectUtils.isProjectEmpty(project)) { - CommandUtil.printError(this.errStream, "package is empty. Please add at least one .bal file.", null, false); - CommandUtil.exitError(this.exitWhenFinish); - return; - } - // Sets the debug port as a system property, which will be used when setting up debug args before running tests. if (this.debugPort != null) { System.setProperty(SYSTEM_PROP_BAL_DEBUG, this.debugPort); @@ -307,7 +322,7 @@ public void execute() { return; } } - if (excludes != null && excludes.equals("")) { + if (excludes != null && excludes.isEmpty()) { this.outStream.println("warning: ignoring --excludes flag since given exclusion list is empty"); } } else { @@ -334,6 +349,19 @@ public void execute() { "flag is not set"); } + if (!project.buildOptions().cloud().isEmpty() && project.buildOptions().codeCoverage()) { + this.outStream.println("WARNING: Code coverage generation is not supported with Ballerina cloud test"); + } + + if (!project.buildOptions().cloud().isEmpty() && this.rerunTests) { + this.outStream.println("WARNING: Rerun failed tests is not supported with Ballerina cloud test"); + } + + if (!project.buildOptions().cloud().isEmpty() && project.buildOptions().testReport()) { + this.outStream.println("WARNING: Test report generation is not supported with Ballerina cloud test"); + } + + // Run pre-build tasks to have the project reloaded. // In code coverage generation, the module map is duplicated. // Therefore, the project needs to be reloaded beforehand to provide the latest project instance @@ -341,6 +369,7 @@ public void execute() { // Hence, below tasks are executed before extracting the module map from the project. TaskExecutor preBuildTaskExecutor = new TaskExecutor.TaskBuilder() .addTask(new CleanTargetCacheDirTask(), isSingleFile) // clean the target cache dir(projects only) + .addTask(new CleanTargetBinTestsDirTask(), (isSingleFile || project.buildOptions().cloud().isEmpty())) .addTask(new RunBuildToolsTask(outStream), isSingleFile) // run build tools .build(); preBuildTaskExecutor.executeTasks(project); @@ -361,12 +390,17 @@ public void execute() { .addTask(new CompileTask(outStream, errStream, false, false, isPackageModified, buildOptions.enableCache())) // .addTask(new CopyResourcesTask(), listGroups) // merged with CreateJarTask - .addTask(new RunTestsTask(outStream, errStream, rerunTests, groupList, disableGroupList, testList, - includes, coverageFormat, moduleMap, listGroups, excludes, cliArgs, isParallelExecution), - project.buildOptions().nativeImage()) + .addTask(new CreateTestExecutableTask(outStream, groupList, disableGroupList, testList, listGroups, + cliArgs, isParallelExecution), + project.buildOptions().cloud().isEmpty()) + .addTask(new RunTestsTask(outStream, errStream, rerunTests, groupList, disableGroupList, + testList, includes, coverageFormat, moduleMap, listGroups, excludes, cliArgs, + isParallelExecution), + (project.buildOptions().nativeImage() || + !project.buildOptions().cloud().isEmpty())) .addTask(new RunNativeImageTestTask(outStream, rerunTests, groupList, disableGroupList, - testList, includes, coverageFormat, moduleMap, listGroups, isParallelExecution), - !project.buildOptions().nativeImage()) + testList, includes, coverageFormat, moduleMap, listGroups, isParallelExecution), + (!project.buildOptions().nativeImage() || !project.buildOptions().cloud().isEmpty())) .addTask(new DumpBuildTimeTask(outStream), !project.buildOptions().dumpBuildTime()) .build(); @@ -387,13 +421,15 @@ private BuildOptions constructBuildOptions() { .setObservabilityIncluded(observabilityIncluded) .setDumpBuildTime(dumpBuildTime) .setSticky(sticky) + .setCloud(cloud) .setDumpGraph(dumpGraph) .setDumpRawGraphs(dumpRawGraphs) .setNativeImage(nativeImage) .setEnableCache(enableCache) .disableSyntaxTreeCaching(disableSyntaxTreeCaching) - .setGraalVMBuildOptions(graalVMBuildOptions); - + .setGraalVMBuildOptions(graalVMBuildOptions) + .setShowDependencyDiagnostics(showDependencyDiagnostics) + .setOptimizeDependencyCompilation(optimizeDependencyCompilation); if (targetDir != null) { buildOptionsBuilder.targetDir(targetDir.toString()); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/ToolCommand.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/ToolCommand.java index 87d549c36bcb..7aa91b6194b5 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/ToolCommand.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/cmd/ToolCommand.java @@ -40,7 +40,6 @@ import org.ballerinalang.central.client.exceptions.PackageAlreadyExistsException; import org.ballerinalang.central.client.model.Tool; import org.ballerinalang.central.client.model.ToolSearchResult; -import org.ballerinalang.toml.exceptions.SettingsTomlException; import org.wso2.ballerinalang.compiler.util.Names; import org.wso2.ballerinalang.util.RepoUtils; import picocli.CommandLine; @@ -514,20 +513,16 @@ private boolean isToolAvailableInLocalRepo(String toolId, String version) { private void pullToolFromCentral(String supportedPlatform, Path balaCacheDirPath) throws CentralClientException { Settings settings; - try { - settings = RepoUtils.readSettings(); - // Ignore Settings.toml diagnostics in the pull command - } catch (SettingsTomlException e) { - // Ignore 'Settings.toml' parsing errors and return empty Settings object - settings = Settings.from(); - } + settings = RepoUtils.readSettings(); + // Ignore Settings.toml diagnostics in the pull command + System.setProperty(CentralClientConstants.ENABLE_OUTPUT_STREAM, "true"); CentralAPIClient client = new CentralAPIClient(RepoUtils.getRemoteRepoURL(), initializeProxy(settings.getProxy()), settings.getProxy().username(), settings.getProxy().password(), getAccessTokenOfCLI(settings), settings.getCentral().getConnectTimeout(), settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(), - settings.getCentral().getCallTimeout()); + settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries()); String[] toolInfo = client.pullTool(toolId, version, balaCacheDirPath, supportedPlatform, RepoUtils.getBallerinaVersion(), false); boolean isPulled = Boolean.parseBoolean(toolInfo[0]); @@ -655,19 +650,15 @@ private void deleteCachedToolVersion(String org, String name, String version) { private void searchToolsInCentral(String keyword) { try { Settings settings; - try { - settings = RepoUtils.readSettings(); - // Ignore Settings.toml diagnostics in the search command - } catch (SettingsTomlException e) { - // Ignore 'Settings.toml' parsing errors and return empty Settings object - settings = Settings.from(); - } + settings = RepoUtils.readSettings(); + // Ignore Settings.toml diagnostics in the search command + CentralAPIClient client = new CentralAPIClient(RepoUtils.getRemoteRepoURL(), initializeProxy(settings.getProxy()), settings.getProxy().username(), settings.getProxy().password(), getAccessTokenOfCLI(settings), settings.getCentral().getConnectTimeout(), settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(), - settings.getCentral().getCallTimeout()); + settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries()); boolean foundTools = false; String supportedPlatform = Arrays.stream(JvmTarget.values()) .map(JvmTarget::code) @@ -675,7 +666,7 @@ private void searchToolsInCentral(String keyword) { ToolSearchResult toolSearchResult = client.searchTool(keyword, supportedPlatform, RepoUtils.getBallerinaVersion()); List tools = toolSearchResult.getTools(); - if (tools != null && tools.size() > 0) { + if (tools != null && !tools.isEmpty()) { foundTools = true; printTools(toolSearchResult.getTools(), RepoUtils.getTerminalWidth()); } @@ -817,20 +808,16 @@ private void updateToolToLatestVersion() { private String getLatestVersionForUpdateCommand(String supportedPlatforms, BalToolsManifest.Tool tool) throws CentralClientException { Settings settings; - try { - settings = RepoUtils.readSettings(); - // Ignore Settings.toml diagnostics in the pull command - } catch (SettingsTomlException e) { - // Ignore 'Settings.toml' parsing errors and return empty Settings object - settings = Settings.from(); - } + settings = RepoUtils.readSettings(); + // Ignore Settings.toml diagnostics in the pull command + System.setProperty(CentralClientConstants.ENABLE_OUTPUT_STREAM, "true"); CentralAPIClient client = new CentralAPIClient(RepoUtils.getRemoteRepoURL(), initializeProxy(settings.getProxy()), settings.getProxy().username(), settings.getProxy().password(), getAccessTokenOfCLI(settings), settings.getCentral().getConnectTimeout(), settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(), - settings.getCentral().getCallTimeout()); + settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries()); List versions = client.getPackageVersions(tool.org(), tool.name(), supportedPlatforms, RepoUtils.getBallerinaVersion()); return getLatestVersion(versions, tool.version()); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/BLauncherException.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/BLauncherException.java index e0e182ed5ebd..d0dcdb90737a 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/BLauncherException.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/BLauncherException.java @@ -26,7 +26,7 @@ * @since 0.8.0 */ public class BLauncherException extends RuntimeException { - private List detailedMessages = new ArrayList<>(); + private final List detailedMessages = new ArrayList<>(); public List getDetailedMessages() { return detailedMessages; diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/BallerinaCliCommands.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/BallerinaCliCommands.java index 4c047f3967a1..e65001c91377 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/BallerinaCliCommands.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/BallerinaCliCommands.java @@ -22,12 +22,14 @@ * * @since 0.970.0 */ -public class BallerinaCliCommands { +public final class BallerinaCliCommands { public static final String DEFAULT = "default"; public static final String HELP = "help"; public static final String VERSION = "version"; public static final String RUN = "run"; - public static final String ENCRYPT = "encrypt"; public static final String HOME = "home"; + + private BallerinaCliCommands() { + } } diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/LauncherUtils.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/LauncherUtils.java index bec861a1fe25..5514f45bc55a 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/LauncherUtils.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/LauncherUtils.java @@ -28,10 +28,11 @@ import java.io.IOException; import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -45,16 +46,19 @@ * * @since 0.8.0 */ -public class LauncherUtils { +public final class LauncherUtils { + + private LauncherUtils() { + } public static Path getSourceRootPath(String sourceRoot) { // Get source root path. Path sourceRootPath; if (sourceRoot == null || sourceRoot.isEmpty()) { - sourceRootPath = Paths.get(System.getProperty("user.dir")); + sourceRootPath = Path.of(System.getProperty("user.dir")); } else { try { - sourceRootPath = Paths.get(sourceRoot).toRealPath(LinkOption.NOFOLLOW_LINKS); + sourceRootPath = Path.of(sourceRoot).toRealPath(LinkOption.NOFOLLOW_LINKS); } catch (IOException e) { throw new RuntimeException("error reading from directory: " + sourceRoot + " reason: " + e.getMessage(), e); @@ -82,17 +86,24 @@ public static BLauncherException createLauncherException(String errorMsg) { public static BLauncherException createLauncherException(String errorPrefix, Throwable cause) { String message; - if (cause instanceof BError) { - message = ((BError) cause).getPrintableStackTrace(); + if (cause instanceof BError bError) { + message = bError.getPrintableStackTrace(); } else { - message = cause.toString(); + StringWriter sw = new StringWriter(); + cause.printStackTrace(new PrintWriter(sw)); + message = sw.toString(); } BLauncherException launcherException = new BLauncherException(); launcherException.addMessage("error: " + errorPrefix + message); return launcherException; } - static void printLauncherException(BLauncherException e, PrintStream outStream) { + + public static String prepareCompilerErrorMessage(String message) { + return "error: " + LauncherUtils.makeFirstLetterLowerCase(message); + } + + public static void printLauncherException(BLauncherException e, PrintStream outStream) { List errorMessages = e.getMessages(); errorMessages.forEach(outStream::println); } @@ -121,12 +132,10 @@ static String generateGeneralHelp(Map subCommands) { .sorted().toList(); if (!toolNames.isEmpty()) { - toolNames.forEach(toolName -> { - balToolsManifest.getActiveTool(toolName).ifPresent(tool -> { + toolNames.forEach(toolName -> + balToolsManifest.getActiveTool(toolName).ifPresent(tool -> activeToolsVsRepos.put(toolName, tool.repository() == null ? "" : "[" + tool.repository() - .toUpperCase() + "] "); - }); - }); + .toUpperCase() + "] "))); helpBuilder.append("\n\n Tool Commands:"); toolNames.forEach(key -> generateCommandDescription(subCommands.get(key), helpBuilder, activeToolsVsRepos.get(key))); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/Main.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/Main.java index 7b2cb7d67530..4b0d8a039e21 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/Main.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/Main.java @@ -38,13 +38,15 @@ import static io.ballerina.cli.cmd.Constants.HELP_OPTION; import static io.ballerina.cli.cmd.Constants.HELP_SHORT_OPTION; import static io.ballerina.cli.cmd.Constants.VERSION_COMMAND; +import static io.ballerina.cli.launcher.LauncherUtils.prepareCompilerErrorMessage; /** * This class executes a Ballerina program. * * @since 0.8.0 */ -public class Main { +public final class Main { + private static final String UNMATCHED_ARGUMENT_PREFIX = "Unmatched argument"; private static final String MISSING_REQUIRED_PARAMETER_PREFIX = "Missing required parameter"; private static final String COMPILATION_ERROR_MESSAGE = "compilation contains errors"; @@ -52,6 +54,9 @@ public class Main { private static final PrintStream errStream = System.err; private static final PrintStream outStream = System.out; + private Main() { + } + public static void main(String... args) { try { Optional optionalInvokedCmd = getInvokedCmd(args); @@ -123,12 +128,12 @@ private static Optional getInvokedCmd(String... args) { List parsedCommands = cmdParser.parse(args); - if (defaultCmd.argList.size() > 0 && cmdParser.getSubcommands().get(defaultCmd.argList.get(0)) == null) { + if (!defaultCmd.argList.isEmpty() && cmdParser.getSubcommands().get(defaultCmd.argList.get(0)) == null) { throw LauncherUtils.createUsageExceptionWithHelp("unknown command '" + defaultCmd.argList.get(0) + "'"); } - if (parsedCommands.size() < 1 || defaultCmd.helpFlag) { + if (parsedCommands.isEmpty() || defaultCmd.helpFlag) { if (parsedCommands.size() > 1) { defaultCmd.argList.add(parsedCommands.get(1).getCommandName()); } @@ -208,10 +213,6 @@ private static void printBallerinaDistPath() { } } - private static String prepareCompilerErrorMessage(String message) { - return "error: " + LauncherUtils.makeFirstLetterLowerCase(message); - } - private static String getFirstUnknownArg(String errorMessage) { String optionsString = errorMessage.split(":")[1]; return (optionsString.split(","))[0].trim(); @@ -230,6 +231,7 @@ private static class HelpCmd implements BLauncherCmd { private CommandLine parentCmdParser; + @Override public void execute() { Map subCommands = parentCmdParser.getSubcommands(); if (helpCommands == null) { @@ -286,6 +288,7 @@ private static class VersionCmd implements BLauncherCmd { private CommandLine parentCmdParser; + @Override public void execute() { if (helpFlag) { printUsageInfo(BallerinaCliCommands.VERSION); @@ -334,6 +337,7 @@ private static class HomeCmd implements BLauncherCmd { private CommandLine parentCmdParser; + @Override public void execute() { if (helpFlag) { printUsageInfo(BallerinaCliCommands.HOME); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/RuntimePanicException.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/RuntimePanicException.java index 36789cbd124b..f891374ad36c 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/RuntimePanicException.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/RuntimePanicException.java @@ -24,7 +24,7 @@ */ public class RuntimePanicException extends RuntimeException { - private int exitCode; + private final int exitCode; /** * Constructs a new {@link RuntimePanicException} with the specified exit code. diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/util/BCompileUtil.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/util/BCompileUtil.java index 0484107b8811..d54baa503df6 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/util/BCompileUtil.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/util/BCompileUtil.java @@ -18,30 +18,23 @@ import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.nio.file.Paths; /** * Utility methods for compile Ballerina files. * * @since 0.94 */ -public class BCompileUtil { +public final class BCompileUtil { - //TODO find a way to remove below line. - private static Path resourceDir = Paths.get("src/test/resources").toAbsolutePath(); + private BCompileUtil() { + } public static String readFileAsString(String path) throws IOException { - InputStream is = ClassLoader.getSystemResourceAsStream(path); - InputStreamReader inputStreamREader = null; - BufferedReader br = null; StringBuilder sb = new StringBuilder(); - try { - inputStreamREader = new InputStreamReader(is, StandardCharsets.UTF_8); - br = new BufferedReader(inputStreamREader); + try (BufferedReader br = new BufferedReader( + new InputStreamReader(ClassLoader.getSystemResourceAsStream(path), StandardCharsets.UTF_8))) { String content = br.readLine(); if (content == null) { return sb.toString(); @@ -52,19 +45,6 @@ public static String readFileAsString(String path) throws IOException { while ((content = br.readLine()) != null) { sb.append('\n').append(content); } - } finally { - if (inputStreamREader != null) { - try { - inputStreamREader.close(); - } catch (IOException ignore) { - } - } - if (br != null) { - try { - br.close(); - } catch (IOException ignore) { - } - } } return sb.toString(); } diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/util/BFileUtil.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/util/BFileUtil.java deleted file mode 100644 index 54e9018d2201..000000000000 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/util/BFileUtil.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. 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.cli.launcher.util; - -import java.io.IOException; -import java.nio.file.CopyOption; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.BasicFileAttributes; - -import static io.ballerina.cli.launcher.LauncherUtils.createLauncherException; - -/** - * Utility methods for doing file operations. - * - * @since 0.975.0 - */ -public class BFileUtil { - - private static final String IGNORE = ".gitignore"; - - private BFileUtil() {} - - /** - * Copy a file or directory to a target location. - * - * @param sourcePath File or directory to be copied - * @param targetPath Target location - */ - public static void copy(Path sourcePath, Path targetPath) { - try { - Files.walkFileTree(sourcePath, new SimpleFileVisitor() { - - @Override - public FileVisitResult visitFileFailed(Path file, IOException exc) { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { - if (Files.exists(dir)) { - Files.createDirectories(targetPath.resolve(sourcePath.relativize(dir))); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - if (!IGNORE.equals(file.getFileName().toString()) && Files.exists(file)) { - CopyOption[] option = { - StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES - }; - Files.copy(file, targetPath.resolve(sourcePath.relativize(file)), option); - } - return FileVisitResult.CONTINUE; - } - }); - } catch (IOException e) { - throw createLauncherException( - "error occured while copying from '" + sourcePath + "' " + "to '" + targetPath + "'"); - } - } - - /** - * Delete a file or directory. - * - * @param path Path to the file or directory - */ - public static void delete(Path path) { - try { - Files.walkFileTree(path, new SimpleFileVisitor() { - - @Override - public FileVisitResult visitFileFailed(Path file, IOException exc) { - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - if (Files.exists(file)) { - Files.delete(file); - } - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { - if (Files.exists(dir)) { - Files.list(dir).forEach(BFileUtil::delete); - } - return FileVisitResult.CONTINUE; - } - }); - } catch (IOException e) { - throw createLauncherException("error occurred while deleting '" + path + "'"); - } - } - -} diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/util/BalToolsUtil.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/util/BalToolsUtil.java index 06805bdeafa0..d92abf44ff4e 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/util/BalToolsUtil.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/launcher/util/BalToolsUtil.java @@ -44,7 +44,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; import java.util.stream.Stream; import static io.ballerina.cli.cmd.Constants.ADD_COMMAND; @@ -96,7 +95,8 @@ * * @since 2201.8.0 */ -public class BalToolsUtil { +public final class BalToolsUtil { + private static final String TOOL = "tool"; private static final String LIBS = "libs"; @@ -114,7 +114,7 @@ public class BalToolsUtil { UPDATE_COMMAND, START_LANG_SERVER_COMMAND, START_DEBUG_ADAPTER_COMMAND, HELP_COMMAND, HOME_COMMAND, GENCACHE_COMMAND); // if a command is a built-in tool command, add it to this list - private static final List builtInToolCommands = Arrays.asList(); + private static final List builtInToolCommands = List.of(); private static final Path balToolsTomlPath = RepoUtils.createAndGetHomeReposPath().resolve( Path.of(CONFIG_DIR, BAL_TOOLS_TOML)); @@ -122,6 +122,9 @@ public class BalToolsUtil { .resolve(REPOSITORIES_DIR).resolve(CENTRAL_REPOSITORY_CACHE_NAME) .resolve(ProjectConstants.BALA_DIR_NAME); + private BalToolsUtil() { + } + public static boolean isNonBuiltInToolCommand(String commandName) { return isToolCommand(commandName) && !builtInToolCommands.contains(commandName); } @@ -185,7 +188,7 @@ private static List getToolCommandJarAndDependencyJars(String commandName) .resolve(TOOL).resolve(LIBS) .toFile())) .flatMap(List::stream) - .collect(Collectors.toList()); + .toList(); } Optional toolOpt = balToolsManifest.getActiveTool(commandName); @@ -276,7 +279,7 @@ public static void updateOldBalToolsToml() { } catch (ProjectException ignore) { return false; } - })).map(File::getName).collect(Collectors.toList()); + })).map(File::getName).toList(); Optional latestVersion = getLatestVersion(versions); versions.stream().forEach(version -> { diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/CleanTargetBinTestsDirTask.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/CleanTargetBinTestsDirTask.java new file mode 100644 index 000000000000..5ea13569a839 --- /dev/null +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/CleanTargetBinTestsDirTask.java @@ -0,0 +1,42 @@ +// 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.cli.task; + +import io.ballerina.projects.Project; +import io.ballerina.projects.ProjectException; +import io.ballerina.projects.internal.model.Target; + +import java.io.IOException; + +import static io.ballerina.cli.launcher.LauncherUtils.createLauncherException; + +/** + * Cleans up the target bin's tests directory. + * + * @since 2201.9.0 + */ +public class CleanTargetBinTestsDirTask implements Task { + @Override + public void execute(Project project) { + try { + Target target = new Target(project.targetDir()); + target.cleanBinTests(); + } catch (IOException | ProjectException e) { + throw createLauncherException("unable to clean the target bin's tests directory: " + e.getMessage()); + } + } +} diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/CompileTask.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/CompileTask.java index ba0bd8f7aeba..eee746244286 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/CompileTask.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/CompileTask.java @@ -50,6 +50,7 @@ import java.util.Set; import static io.ballerina.cli.launcher.LauncherUtils.createLauncherException; +import static io.ballerina.projects.internal.ProjectDiagnosticErrorCode.CORRUPTED_DEPENDENCIES_TOML; import static io.ballerina.projects.util.ProjectConstants.DOT; import static io.ballerina.projects.util.ProjectConstants.TOOL_DIAGNOSTIC_CODE_PREFIX; @@ -86,6 +87,9 @@ public CompileTask(PrintStream out, @Override public void execute(Project project) { + if (ProjectUtils.isProjectEmpty(project) && skipCompilationForBalPack(project)) { + throw createLauncherException("package is empty. Please add at least one .bal file."); + } this.out.println("Compiling source"); String sourceName; @@ -204,10 +208,22 @@ public void execute(Project project) { throw createLauncherException("package resolution contains errors"); } + // Add corrupted dependencies toml diagnostic + project.currentPackage().dependencyManifest().diagnostics().diagnostics().forEach(diagnostic -> { + if (diagnostic.diagnosticInfo().code().equals(CORRUPTED_DEPENDENCIES_TOML.diagnosticId())) { + diagnostics.add(diagnostic); + } + }); + // Package resolution is successful. Continue compiling the package. if (project.buildOptions().dumpBuildTime()) { start = System.currentTimeMillis(); } + + String projectLoadingDiagnostic = ProjectUtils.getProjectLoadingDiagnostic(); + if (projectLoadingDiagnostic != null && !projectLoadingDiagnostic.isEmpty()) { + out.println(projectLoadingDiagnostic); + } PackageCompilation packageCompilation = project.currentPackage().getCompilation(); if (project.buildOptions().dumpBuildTime()) { BuildTime.getInstance().packageCompilationDuration = System.currentTimeMillis() - start; @@ -317,4 +333,16 @@ private void addDiagnosticForProvidedPlatformLibs(Project project, List out.println("\n" + d.toString())); } @@ -132,7 +118,7 @@ public void execute(Project project) { throw createLauncherException(e.getMessage()); } - if (!project.buildOptions().nativeImage()) { + if (!project.buildOptions().nativeImage() && !isHideTaskOutput) { Path relativePathToExecutable = currentDir.relativize(executablePath); if (project.buildOptions().getTargetPath() != null) { @@ -149,13 +135,30 @@ public void execute(Project project) { // notify plugin // todo following call has to be refactored after introducing new plugin architecture - notifyPlugins(project, target); + BuildUtils.notifyPlugins(project, target); } - private void notifyPlugins(Project project, Target target) { - ServiceLoader processorServiceLoader = ServiceLoader.load(CompilerPlugin.class); - for (CompilerPlugin plugin : processorServiceLoader) { - plugin.codeGenerated(project, target); + private Target getTarget(Project project) { + Target target; + try { + if (project.kind().equals(ProjectKind.BUILD_PROJECT)) { + target = new Target(project.targetDir()); + } else { + target = new Target(Files.createTempDirectory("ballerina-cache" + System.nanoTime())); + target.setOutputPath(getExecutablePath(project)); + } + } catch (IOException e) { + throw createLauncherException("unable to resolve target path:" + e.getMessage()); + } catch (ProjectException e) { + throw createLauncherException("unable to create executable:" + e.getMessage()); + } + return target; + } + private Path getExecutablePath(Project project, Target target) { + try { + return target.getExecutablePath(project.currentPackage()).toAbsolutePath().normalize(); + } catch (IOException e) { + throw createLauncherException(e.getMessage()); } } @@ -179,7 +182,7 @@ private Path getExecutablePath(Project project) { // If the --output does not have an extension, append the .jar extension if (!FileUtils.hasExtension(this.output)) { - return Paths.get(this.output.toString() + BLANG_COMPILED_JAR_EXT); + return Path.of(this.output.toString() + BLANG_COMPILED_JAR_EXT); } return this.output; diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/CreateTestExecutableTask.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/CreateTestExecutableTask.java new file mode 100644 index 000000000000..64ab0d001343 --- /dev/null +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/CreateTestExecutableTask.java @@ -0,0 +1,377 @@ +// 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.cli.task; + +import io.ballerina.cli.utils.BuildTime; +import io.ballerina.cli.utils.BuildUtils; +import io.ballerina.cli.utils.NativeUtils; +import io.ballerina.cli.utils.TestUtils; +import io.ballerina.projects.EmitResult; +import io.ballerina.projects.JBallerinaBackend; +import io.ballerina.projects.JarLibrary; +import io.ballerina.projects.JvmTarget; +import io.ballerina.projects.Module; +import io.ballerina.projects.ModuleDescriptor; +import io.ballerina.projects.ModuleName; +import io.ballerina.projects.PackageCompilation; +import io.ballerina.projects.Project; +import io.ballerina.projects.ProjectException; +import io.ballerina.projects.ProjectKind; +import io.ballerina.projects.TestEmitArgs; +import io.ballerina.projects.internal.model.Target; +import io.ballerina.projects.util.ProjectConstants; +import io.ballerina.tools.diagnostics.Diagnostic; +import org.ballerinalang.test.runtime.entity.TestSuite; +import org.ballerinalang.test.runtime.util.TesterinaConstants; +import org.ballerinalang.testerina.core.TestProcessor; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.zip.ZipFile; + +import static io.ballerina.cli.launcher.LauncherUtils.createLauncherException; +import static io.ballerina.cli.utils.FileUtils.getFileNameWithoutExtension; +import static io.ballerina.cli.utils.NativeUtils.modifyJarForFunctionMock; +import static io.ballerina.cli.utils.TestUtils.createTestSuitesForProject; +import static io.ballerina.projects.util.ProjectConstants.BLANG_COMPILED_JAR_EXT; +import static org.ballerinalang.test.runtime.util.TesterinaConstants.MODIFIED_JAR_SUFFIX; + +/** + * Task for creating the executable testable jar(s) for the ballerina project. + * + * @since 2201.9.0 + */ + +public class CreateTestExecutableTask implements Task { + private final transient PrintStream out; + private final String groupList; + private final String disableGroupList; + private final boolean report; + private final boolean coverage; + private final boolean isRerunTestExecution; + private final String singleExecTests; + private final boolean listGroups; + private final List cliArgs; + private final boolean isParallelExecution; + + public CreateTestExecutableTask(PrintStream out, String groupList, String disableGroupList, String singleExecTests, + boolean listGroups, String[] cliArgs, boolean isParallelExecution) { + this.out = out; + this.groupList = groupList; + this.disableGroupList = disableGroupList; + this.report = false; // This is set to false because the report is not generated in this task + this.coverage = false; // This is set to false because the coverage is not generated in this task + this.isRerunTestExecution = false; // This is set to false because the tests are not rerun in this task + this.singleExecTests = singleExecTests; + this.listGroups = listGroups; + this.cliArgs = List.of(cliArgs); + this.isParallelExecution = isParallelExecution; + } + + @Override + public void execute(Project project) { + Target target = getTarget(project); + try { + PackageCompilation pkgCompilation = project.currentPackage().getCompilation(); + JBallerinaBackend jBallerinaBackend = JBallerinaBackend.from(pkgCompilation, JvmTarget.JAVA_17); + List emitDiagnostics = new ArrayList<>(); + Path testCachePath = target.getTestsCachePath(); + long start = 0; + if (project.buildOptions().dumpBuildTime()) { + start = System.currentTimeMillis(); + } + HashSet testExecDependencies = new HashSet<>(); + Map testSuiteMap = new HashMap<>(); + + // Create and Write the test suite json that is used to execute the tests + boolean suiteCreated = createTestSuiteForCloudArtifacts(project, jBallerinaBackend, target, testSuiteMap); + + if (suiteCreated) { + // Write the cmd args to a file, so it can be read on c2c side + writeCmdArgsToFile(getTestExecutableBasePath(target), + target, TestUtils.getJsonFilePath(testCachePath)); + + if (project.buildOptions().nativeImage()) { + NativeUtils.createReflectConfig(target.getNativeConfigPath(), + project.currentPackage(), testSuiteMap); + // Traverse the map and check if a suite has mock functions + boolean hasMockFunctions = false; + for (Map.Entry entry : testSuiteMap.entrySet()) { + if (!entry.getValue().getMockFunctionNamesMap().isEmpty()) { + hasMockFunctions = true; + break; + } + } + if (hasMockFunctions) { + perModuleFatJarGeneration(testSuiteMap, target, jBallerinaBackend, emitDiagnostics, project); + } else { + standaloneFatJarGeneration(project, jBallerinaBackend, target, testExecDependencies, + testCachePath, emitDiagnostics); + } + } else { + standaloneFatJarGeneration(project, jBallerinaBackend, target, testExecDependencies, + testCachePath, emitDiagnostics); + } + } + if (project.buildOptions().dumpBuildTime()) { + BuildTime.getInstance().emitArtifactDuration = System.currentTimeMillis() - start; + BuildTime.getInstance().compile = false; + } + + // Print warnings for conflicted jars + if (!jBallerinaBackend.conflictedJars().isEmpty()) { + out.println("\twarning: Detected conflicting jar files:"); + for (JBallerinaBackend.JarConflict conflict : jBallerinaBackend.conflictedJars()) { + out.println(conflict.getWarning(project.buildOptions().listConflictedClasses())); + } + } + if (!emitDiagnostics.isEmpty()) { + emitDiagnostics.forEach(d -> out.println("\n" + d.toString())); + } + } catch (ProjectException | IOException e) { + throw createLauncherException(e.getMessage()); + } + // notify plugin + // todo following call has to be refactored after introducing new plugin architecture + // Similar case as in CreateExecutableTask.java + BuildUtils.notifyPlugins(project, target); + TestUtils.cleanTempCache(project, target.path()); + } + + private void standaloneFatJarGeneration(Project project, JBallerinaBackend jBallerinaBackend, Target target, + HashSet testExecDependencies, Path testCachePath, + List emitDiagnostics) throws IOException { + // Get all the dependencies required for test execution for each module + for (ModuleDescriptor moduleDescriptor : + project.currentPackage().moduleDependencyGraph().toTopologicallySortedList()) { + Module module = project.currentPackage().module(moduleDescriptor.name()); + testExecDependencies.addAll(jBallerinaBackend.jarResolver() + .getJarFilePathsRequiredForTestExecution(module.moduleName()) + ); + } + + String jarName = project.currentPackage().packageName().toString(); + if (jarName.equals(ProjectConstants.DOT)) { + Optional projectSourceRootFileName = Optional.ofNullable(project.sourceRoot().getFileName()); + if (projectSourceRootFileName.isPresent()) { + jarName = getFileNameWithoutExtension(projectSourceRootFileName.get()); + } else { + throw new IllegalStateException("unable to resolve project source root"); + } + } + + Path testExecutablePath = getTestExecutableBasePath(target).resolve( + jarName + ProjectConstants.TEST_UBER_JAR_SUFFIX + ProjectConstants.BLANG_COMPILED_JAR_EXT); + + List moduleJarPaths = TestUtils.getModuleJarPaths(jBallerinaBackend, project.currentPackage()); + List excludedClasses = new ArrayList<>(); + for (Path moduleJarPath : moduleJarPaths) { + try (ZipFile zipFile = new ZipFile(moduleJarPath.toFile())) { + zipFile.stream().forEach(entry -> { + if (entry.getName().endsWith(ProjectConstants.JAVA_CLASS_EXT)) { + excludedClasses.add(entry.getName().replace(File.separator, ProjectConstants.DOT) + .replace(ProjectConstants.JAVA_CLASS_EXT, "")); + } + }); + } + } + + // Create the single fat jar for all the test modules that includes the test suite json + EmitResult result = jBallerinaBackend.emit( + new TestEmitArgs(JBallerinaBackend.OutputType.TEST, testExecutablePath, testExecDependencies, + TestUtils.getJsonFilePath(testCachePath), TestUtils.getJsonFilePathInFatJar(File.separator), + excludedClasses, ProjectConstants.EXCLUDED_CLASSES_FILE)); + emitDiagnostics.addAll(result.diagnostics().diagnostics()); + } + + private void perModuleFatJarGeneration(Map testSuiteMap, Target target, + JBallerinaBackend jBallerinaBackend, List emitDiagnostics, + Project project) + throws IOException { + // Clone the map to the count of test suites + List> clonedMaps = new ArrayList<>(); + testSuiteMap.keySet().forEach(mapEntry -> { + Map clonedMap = new HashMap<>(); + clonedMap.put(mapEntry, testSuiteMap.get(mapEntry)); + clonedMaps.add(clonedMap); + }); + + List moduleNames = project.currentPackage().moduleDependencyGraph() + .toTopologicallySortedList().stream().map(ModuleDescriptor::name).toList(); + // Modify the relevant jars of each test suite + for (Map clonedMap : clonedMaps) { + TestSuite testSuite = clonedMap.values().toArray(new TestSuite[0])[0]; + String moduleName = testSuite.getPackageID(); + NativeUtils.createReflectConfig(target.getNativeConfigPath(), + project.currentPackage(), clonedMap); // Rewrite the reflect config for each module + try { + modifyJarForFunctionMock(testSuite, target, moduleName); + } catch (IOException e) { + throw createLauncherException("error occurred while running tests", e); + } + + ModuleName moduleNameObj = moduleNames.stream().filter(name -> name.toString().equals(moduleName)) + .findFirst().orElseThrow(); + // Remove the mock function classes from the test suite + testSuite.removeAllMockFunctions(); + Collection testDependencies = jBallerinaBackend.jarResolver() + .getJarFilePathsRequiredForTestExecution(moduleNameObj); + + // Filter the testDependencies from the testSuite's test dependencies + Collection requiredDependencies = testSuite.getTestExecutionDependencies().stream() + .map(Path::of).toList(); + HashSet filteredTestDependencies = new HashSet<>(); + requiredDependencies.forEach(neededDependency -> { + String comparingStr = MODIFIED_JAR_SUFFIX; + Optional neededDependencyFileName = Optional.ofNullable(neededDependency.getFileName()); + if (neededDependencyFileName.isPresent()) { + String requiredDependencyFileName = neededDependencyFileName.get().toString(); + if (!requiredDependencyFileName.contains(comparingStr)) { + return; + } + String originalFileName = requiredDependencyFileName.replace(comparingStr, ""); + Optional foundDependency = testDependencies.stream().filter(dep -> { + Optional depFileName = Optional.ofNullable(dep.path().getFileName()); + if (depFileName.isPresent()) { + return depFileName.get().toString().contains(originalFileName) && + !depFileName.get().toString().contains(TesterinaConstants.TESTABLE); + } + throw new IllegalStateException("unable to resolve dependency file name"); + }).findFirst(); + if (foundDependency.isEmpty()) { + return; + } + JarLibrary modifiedJarLibrary = new JarLibrary(neededDependency, + foundDependency.get().scope()); + filteredTestDependencies.add(modifiedJarLibrary); + testDependencies.remove(foundDependency.get()); + } else { + throw new IllegalStateException("unable to resolve dependency file name"); + } + }); + + // Add the remaining dependencies + filteredTestDependencies.addAll(testDependencies); + + // Remove the test execution dependencies from the test suite and write to json + testSuite.removeAllTestExecutionDependencies(); + try { + TestUtils.writeToTestSuiteJson(clonedMap, target.getTestsCachePath()); + } catch (IOException e) { + throw createLauncherException("error while writing to test suite json file: " + e.getMessage()); + } + + Path testExecutablePath = getTestExecutableBasePath(target).resolve( + moduleName + ProjectConstants.TEST_UBER_JAR_SUFFIX + ProjectConstants.BLANG_COMPILED_JAR_EXT); + // Create the fat jar for the test suite + // excluding class paths are not needed because we do not modify any classes in this scenario + EmitResult result = jBallerinaBackend.emit( + new TestEmitArgs(JBallerinaBackend.OutputType.TEST, testExecutablePath, filteredTestDependencies, + TestUtils.getJsonFilePath(target.getTestsCachePath()), + TestUtils.getJsonFilePathInFatJar(File.separator), new ArrayList<>(), + ProjectConstants.EXCLUDED_CLASSES_FILE)); + emitDiagnostics.addAll(result.diagnostics().diagnostics()); + } + } + + private boolean createTestSuiteForCloudArtifacts(Project project, JBallerinaBackend jBallerinaBackend, + Target target, Map testSuiteMap) { + TestProcessor testProcessor = new TestProcessor(jBallerinaBackend.jarResolver()); + List moduleNamesList = new ArrayList<>(); + List mockClassNames = new ArrayList<>(); + boolean hasTests = createTestSuitesForProject(project, target, testProcessor, testSuiteMap, moduleNamesList, + mockClassNames, this.isRerunTestExecution, this.report, this.coverage); + if (hasTests) { + // Now write the map to a json file + try { + TestUtils.writeToTestSuiteJson(testSuiteMap, target.getTestsCachePath()); + return true; + } catch (IOException e) { + throw createLauncherException("error while writing to test suite json file: " + e.getMessage()); + } + } else { + out.println("\tNo tests found"); + return false; + } + } + + private Path getTestExecutableBasePath(Target target) { + try { + return target.getTestExecutableBasePath(); + } catch (IOException e) { + throw createLauncherException(e.getMessage()); + } + } + + private void writeCmdArgsToFile(Path path, Target target, Path testSuiteJsonPath) { + List cmdArgs = new ArrayList<>(); + TestUtils.appendRequiredArgs( + cmdArgs, target.path().toString(), TestUtils.getJacocoAgentJarPath(), + testSuiteJsonPath.toString(), this.report, + this.coverage, this.groupList, + this.disableGroupList, this.singleExecTests, + this.isRerunTestExecution, this.listGroups, + this.cliArgs, false, this.isParallelExecution + ); + + // Write the cmdArgs to a file in path + Path writingPath = path.resolve(ProjectConstants.TEST_RUNTIME_MAIN_ARGS_FILE); + try (BufferedWriter writer = Files.newBufferedWriter(writingPath)) { + for (String arg : cmdArgs) { + writer.write(arg); + writer.newLine(); + } + } catch (IOException e) { + throw createLauncherException("error while writing to file: " + e.getMessage()); + } + } + + private Target getTarget(Project project) { + Target target; + try { + if (project.kind().equals(ProjectKind.BUILD_PROJECT)) { + target = new Target(project.targetDir()); + } else { + target = new Target(project.targetDir()); + Optional fileName = Optional.ofNullable(project.sourceRoot().getFileName()); + if (fileName.isPresent()) { + target.setOutputPath(target.path().resolve( + getFileNameWithoutExtension(fileName.get()) + BLANG_COMPILED_JAR_EXT + )); + } else { + throw new IllegalStateException("unable to resolve target path"); + } + } + } catch (IOException e) { + throw createLauncherException("unable to resolve target path:" + e.getMessage()); + } catch (ProjectException e) { + throw createLauncherException("unable to create executable:" + e.getMessage()); + } + return target; + } +} diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/DumpBuildTimeTask.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/DumpBuildTimeTask.java index 8fe967b96c1f..d788d73d10d0 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/DumpBuildTimeTask.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/DumpBuildTimeTask.java @@ -31,7 +31,6 @@ import java.io.Writer; import java.nio.charset.StandardCharsets; import java.nio.file.Path; -import java.nio.file.Paths; import static io.ballerina.cli.launcher.LauncherUtils.createLauncherException; @@ -43,7 +42,7 @@ public class DumpBuildTimeTask implements Task { private static final String BUILD_TIME_JSON = "build-time.json"; private final transient PrintStream out; - private final Path currentDir = Paths.get(System.getProperty("user.dir")); + private final Path currentDir = Path.of(System.getProperty("user.dir")); public DumpBuildTimeTask(PrintStream out) { this.out = out; @@ -55,7 +54,7 @@ public void execute(Project project) { BuildTime.getInstance().totalDuration = System.currentTimeMillis() - BuildTime.getInstance().timestamp; BuildTime.getInstance().offline = project.buildOptions().offlineBuild(); Path buildTimeFile = getBuildTimeFilePath(project); - Path buildTimeFileRelativePath = Paths.get(System.getProperty("user.dir")).relativize(buildTimeFile); + Path buildTimeFileRelativePath = Path.of(System.getProperty("user.dir")).relativize(buildTimeFile); this.out.println("\nDumping build time information\n\t" + buildTimeFileRelativePath); persistBuildTimeToFile(buildTimeFile); } diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/ResolveMavenDependenciesTask.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/ResolveMavenDependenciesTask.java index 473e3b1856e9..2cf85aaff8ce 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/ResolveMavenDependenciesTask.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/ResolveMavenDependenciesTask.java @@ -73,7 +73,7 @@ public void execute(Project project) { mavenCustomRepos.add(repository); } - if (mavenCustomRepos.size() > 0) { + if (!mavenCustomRepos.isEmpty()) { for (Map repository : mavenCustomRepos) { if (repository.get("id") != null && repository.get("url") != null && repository.get("username") != null && repository.get("password") != null) { @@ -96,7 +96,7 @@ public void execute(Project project) { } } - if (mavenDependencies.size() > 0) { + if (!mavenDependencies.isEmpty()) { out.println("Resolving Maven dependencies\n\tDownloading dependencies into " + targetRepo); for (Map library : mavenDependencies) { try { diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunBuildToolsTask.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunBuildToolsTask.java index 4ce7bac53449..204385ab65f6 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunBuildToolsTask.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunBuildToolsTask.java @@ -46,7 +46,6 @@ import org.ballerinalang.central.client.CentralAPIClient; import org.ballerinalang.central.client.CentralClientConstants; import org.ballerinalang.central.client.exceptions.CentralClientException; -import org.ballerinalang.toml.exceptions.SettingsTomlException; import org.wso2.ballerinalang.util.RepoUtils; import java.io.File; @@ -172,8 +171,7 @@ public void execute(Project project) { boolean hasOptionErrors = false; try { // validate the options toml and report diagnostics - hasOptionErrors = validateOptionsToml(toolEntry.optionsToml(), toolEntry.id().value(), - toolEntry.type()); + hasOptionErrors = validateOptionsToml(toolEntry.optionsToml(), toolEntry.type()); if (hasOptionErrors) { DiagnosticInfo diagnosticInfo = new DiagnosticInfo( ProjectDiagnosticErrorCode.TOOL_OPTIONS_VALIDATION_FAILED.diagnosticId(), @@ -223,16 +221,16 @@ public void execute(Project project) { this.outStream.println(); } - private boolean validateOptionsToml(Toml optionsToml, String toolId, Tool.Field toolType) throws IOException { + private boolean validateOptionsToml(Toml optionsToml, Tool.Field toolType) throws IOException { if (optionsToml == null) { - return validateEmptyOptionsToml(toolId, toolType); + return validateEmptyOptionsToml(toolType); } FileUtils.validateToml(optionsToml, toolType.value(), toolClassLoader); optionsToml.diagnostics().forEach(outStream::println); return !Diagnostics.filterErrors(optionsToml.diagnostics()).isEmpty(); } - private boolean validateEmptyOptionsToml(String toolId, Tool.Field toolType) throws IOException { + private boolean validateEmptyOptionsToml(Tool.Field toolType) throws IOException { Schema schema = Schema.from(FileUtils.readSchema(toolType.value(), toolClassLoader)); List requiredFields = schema.required(); if (!requiredFields.isEmpty()) { @@ -247,8 +245,6 @@ private boolean validateEmptyOptionsToml(String toolId, Tool.Field toolType) thr } return true; } - this.outStream.printf("WARNING: Validation of tool options of '%s' for '%s' is skipped due to " + - "no tool options found%n", toolType.value(), toolId); return false; } @@ -309,20 +305,16 @@ private void pullToolFromCentral(String toolId, String version) throws CentralCl .collect(Collectors.joining(",")); Path balaCacheDirPath = BuildToolUtils.getCentralBalaDirPath(); Settings settings; - try { - settings = RepoUtils.readSettings(); - // Ignore Settings.toml diagnostics in the pull command - } catch (SettingsTomlException e) { - // Ignore 'Settings.toml' parsing errors and return empty Settings object - settings = Settings.from(); - } + settings = RepoUtils.readSettings(); + // Ignore Settings.toml diagnostics in the pull command + System.setProperty(CentralClientConstants.ENABLE_OUTPUT_STREAM, Boolean.TRUE.toString()); CentralAPIClient client = new CentralAPIClient(RepoUtils.getRemoteRepoURL(), initializeProxy(settings.getProxy()), settings.getProxy().username(), settings.getProxy().password(), getAccessTokenOfCLI(settings), settings.getCentral().getConnectTimeout(), settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(), - settings.getCentral().getCallTimeout()); + settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries()); String[] toolInfo = client.pullTool(toolId, version, balaCacheDirPath, supportedPlatform, RepoUtils.getBallerinaVersion(), false); boolean isPulled = Boolean.parseBoolean(toolInfo[0]); @@ -371,6 +363,6 @@ private static List getToolCommandJarAndDependencyJars(List res .resolve(TOOL).resolve(LIBS) .toFile())) .flatMap(List::stream) - .collect(Collectors.toList()); + .toList(); } } diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunExecutableTask.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunExecutableTask.java index cb7f862c306a..4a8aeda17573 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunExecutableTask.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunExecutableTask.java @@ -20,28 +20,19 @@ import io.ballerina.cli.launcher.RuntimePanicException; import io.ballerina.cli.utils.BuildTime; -import io.ballerina.projects.JBallerinaBackend; -import io.ballerina.projects.JarLibrary; -import io.ballerina.projects.JarResolver; -import io.ballerina.projects.JvmTarget; -import io.ballerina.projects.Module; -import io.ballerina.projects.PackageCompilation; import io.ballerina.projects.Project; import io.ballerina.projects.ProjectException; +import io.ballerina.projects.internal.model.Target; import org.wso2.ballerinalang.util.Lists; -import java.io.File; import java.io.IOException; import java.io.PrintStream; -import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import java.util.StringJoiner; import static io.ballerina.cli.launcher.LauncherUtils.createLauncherException; import static io.ballerina.cli.utils.DebugUtils.getDebugArgs; import static io.ballerina.cli.utils.DebugUtils.isInDebugMode; -import static io.ballerina.runtime.api.constants.RuntimeConstants.MODULE_INIT_CLASS_NAME; import static org.wso2.ballerinalang.compiler.util.ProjectDirConstants.USER_DIR; /** @@ -54,6 +45,8 @@ public class RunExecutableTask implements Task { private final List args; private final transient PrintStream out; private final transient PrintStream err; + private final Target target; + private Process process; /** * Create a task to run the executable. This requires {@link CreateExecutableTask} to be completed. @@ -62,10 +55,11 @@ public class RunExecutableTask implements Task { * @param out output stream * @param err error stream */ - public RunExecutableTask(String[] args, PrintStream out, PrintStream err) { + public RunExecutableTask(String[] args, PrintStream out, PrintStream err, Target target) { this.args = Lists.of(args); this.out = out; this.err = err; + this.target = target; } @Override @@ -80,7 +74,7 @@ public void execute(Project project) { out.println(); try { - this.runGeneratedExecutable(project.currentPackage().getDefaultModule(), project); + this.runGeneratedExecutable(project); } catch (ProjectException e) { throw createLauncherException(e.getMessage()); } @@ -89,48 +83,39 @@ public void execute(Project project) { } } - private void runGeneratedExecutable(Module executableModule, Project project) { - PackageCompilation packageCompilation = project.currentPackage().getCompilation(); - JBallerinaBackend jBallerinaBackend = JBallerinaBackend.from(packageCompilation, JvmTarget.JAVA_17); - JarResolver jarResolver = jBallerinaBackend.jarResolver(); - - String initClassName = JarResolver.getQualifiedClassName( - executableModule.packageInstance().packageOrg().toString(), - executableModule.packageInstance().packageName().toString(), - executableModule.packageInstance().packageVersion().toString(), - MODULE_INIT_CLASS_NAME); + private void runGeneratedExecutable(Project project) { try { List commands = new ArrayList<>(); commands.add(System.getProperty("java.command")); - commands.add("-XX:+HeapDumpOnOutOfMemoryError"); - commands.add("-XX:HeapDumpPath=" + System.getProperty(USER_DIR)); - // Sets classpath with executable thin jar and all dependency jar paths. - commands.add("-cp"); - commands.add(getAllClassPaths(jarResolver)); if (isInDebugMode()) { commands.add(getDebugArgs(err)); } - commands.add(initClassName); + commands.add("-XX:+HeapDumpOnOutOfMemoryError"); + commands.add("-XX:HeapDumpPath=" + System.getProperty(USER_DIR)); + // Sets classpath with executable thin jar and all dependency jar paths. + commands.add("-jar"); + commands.add(this.target.getExecutablePath(project.currentPackage()).toAbsolutePath() + .normalize().toString()); commands.addAll(args); ProcessBuilder pb = new ProcessBuilder(commands).inheritIO(); - Process process = pb.start(); + process = pb.start(); process.waitFor(); int exitValue = process.exitValue(); if (exitValue != 0) { throw new RuntimePanicException(exitValue); } - } catch (IOException | InterruptedException e) { + } catch (IOException e) { throw createLauncherException("Error occurred while running the executable ", e.getCause()); + } catch (InterruptedException e) { + if (process != null && process.isAlive()) { + process.destroy(); + } } } - private String getAllClassPaths(JarResolver jarResolver) { - - StringJoiner cp = new StringJoiner(File.pathSeparator); - jarResolver.getJarFilePathsRequiredForExecution().stream() - .map(JarLibrary::path).map(Path::toString) - .forEach(cp::add); - return cp.toString(); + public void killProcess() { + if (process != null && process.isAlive()) { + process.destroy(); + } } } - diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunNativeImageTestTask.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunNativeImageTestTask.java index d952262c96f9..d9501a3d51f0 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunNativeImageTestTask.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunNativeImageTestTask.java @@ -20,6 +20,7 @@ import io.ballerina.cli.utils.BuildTime; import io.ballerina.cli.utils.GraalVMCompatibilityUtils; +import io.ballerina.cli.utils.NativeUtils; import io.ballerina.cli.utils.TestUtils; import io.ballerina.projects.JBallerinaBackend; import io.ballerina.projects.JarResolver; @@ -34,70 +35,38 @@ import io.ballerina.projects.ProjectKind; import io.ballerina.projects.internal.model.Target; import io.ballerina.projects.util.ProjectConstants; -import org.apache.commons.compress.utils.IOUtils; -import org.ballerinalang.test.runtime.entity.MockFunctionReplaceVisitor; import org.ballerinalang.test.runtime.entity.ModuleStatus; import org.ballerinalang.test.runtime.entity.TestReport; import org.ballerinalang.test.runtime.entity.TestSuite; import org.ballerinalang.test.runtime.util.TesterinaConstants; -import org.ballerinalang.test.runtime.util.TesterinaUtils; import org.ballerinalang.testerina.core.TestProcessor; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; import org.wso2.ballerinalang.util.Lists; import java.io.File; import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; -import java.lang.reflect.Method; -import java.net.URL; -import java.net.URLClassLoader; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Scanner; -import java.util.StringJoiner; -import java.util.jar.JarOutputStream; -import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import static io.ballerina.cli.launcher.LauncherUtils.createLauncherException; -import static io.ballerina.cli.utils.NativeUtils.createReflectConfig; -import static io.ballerina.cli.utils.NativeUtils.getURLList; import static io.ballerina.cli.utils.TestUtils.generateTesterinaReports; import static io.ballerina.projects.util.ProjectConstants.BIN_DIR_NAME; -import static io.ballerina.runtime.api.constants.RuntimeConstants.FILE_NAME_PERIOD_SEPARATOR; -import static java.util.Objects.requireNonNull; +import static io.ballerina.projects.util.ProjectConstants.TESTS_CACHE_DIR_NAME; import static org.ballerinalang.test.runtime.util.TesterinaConstants.CACHE_DIR; -import static org.ballerinalang.test.runtime.util.TesterinaConstants.CLASS_EXTENSION; import static org.ballerinalang.test.runtime.util.TesterinaConstants.DOT; -import static org.ballerinalang.test.runtime.util.TesterinaConstants.DOT_REPLACER; -import static org.ballerinalang.test.runtime.util.TesterinaConstants.HYPHEN; -import static org.ballerinalang.test.runtime.util.TesterinaConstants.JAR_EXTENSION; -import static org.ballerinalang.test.runtime.util.TesterinaConstants.JAVA_17_DIR; -import static org.ballerinalang.test.runtime.util.TesterinaConstants.MOCK_FN_DELIMITER; -import static org.ballerinalang.test.runtime.util.TesterinaConstants.MOCK_FUNC_NAME_PREFIX; -import static org.ballerinalang.test.runtime.util.TesterinaConstants.MOCK_LEGACY_DELIMITER; -import static org.ballerinalang.test.runtime.util.TesterinaConstants.MODIFIED; -import static org.ballerinalang.test.runtime.util.TesterinaConstants.PATH_SEPARATOR; -import static org.ballerinalang.test.runtime.util.TesterinaConstants.TESTABLE; +import static org.ballerinalang.test.runtime.util.TesterinaConstants.TESTERINA_TEST_SUITE; /** * Task for executing tests. @@ -105,13 +74,11 @@ * @since 2.3.0 */ public class RunNativeImageTestTask implements Task { - - private static final String OS = System.getProperty("os.name").toLowerCase(Locale.getDefault()); private static final String WIN_EXEC_EXT = "exe"; private static class StreamGobbler extends Thread { - private InputStream inputStream; - private PrintStream printStream; + private final InputStream inputStream; + private final PrintStream printStream; public StreamGobbler(InputStream inputStream, PrintStream printStream) { this.inputStream = inputStream; @@ -120,9 +87,10 @@ public StreamGobbler(InputStream inputStream, PrintStream printStream) { @Override public void run() { - Scanner sc = new Scanner(inputStream, StandardCharsets.UTF_8); - while (sc.hasNextLine()) { - printStream.println(sc.nextLine()); + try (Scanner sc = new Scanner(inputStream, StandardCharsets.UTF_8)) { + while (sc.hasNextLine()) { + printStream.println(sc.nextLine()); + } } } } @@ -132,9 +100,9 @@ public void run() { private String disableGroupList; private boolean report; private boolean coverage; - private boolean isRerunTestExecution; + private final boolean isRerunTestExecution; private String singleExecTests; - private boolean listGroups; + private final boolean listGroups; private final boolean isParallelExecution; TestReport testReport; @@ -158,124 +126,6 @@ public RunNativeImageTestTask(PrintStream out, boolean rerunTests, String groupL this.isParallelExecution = isParallelExecution; } - - private static byte[] getModifiedClassBytes(String className, List functionNames, TestSuite suite, - ClassLoader classLoader) { - Class functionToMockClass; - try { - functionToMockClass = classLoader.loadClass(className); - } catch (Throwable e) { - throw createLauncherException("failed to load class: " + className); - } - - byte[] classFile = new byte[0]; - boolean readFromBytes = false; - for (Method method1 : functionToMockClass.getDeclaredMethods()) { - if (functionNames.contains(MOCK_FN_DELIMITER + method1.getName())) { - String desugaredMockFunctionName = MOCK_FUNC_NAME_PREFIX + method1.getName(); - String testClassName = TesterinaUtils.getQualifiedClassName(suite.getOrgName(), - suite.getTestPackageID(), suite.getVersion(), - suite.getPackageID().replace(DOT, FILE_NAME_PERIOD_SEPARATOR)); - Class testClass; - try { - testClass = classLoader.loadClass(testClassName); - } catch (Throwable e) { - throw createLauncherException("failed to prepare " + testClassName + " for mocking reason:" + - e.getMessage()); - } - for (Method method2 : testClass.getDeclaredMethods()) { - if (method2.getName().equals(desugaredMockFunctionName)) { - if (!readFromBytes) { - classFile = replaceMethodBody(method1, method2); - readFromBytes = true; - } else { - classFile = replaceMethodBody(classFile, method1, method2); - } - } - } - } else if (functionNames.contains(MOCK_LEGACY_DELIMITER + method1.getName())) { - String key = className + MOCK_LEGACY_DELIMITER + method1.getName(); - String mockFunctionName = suite.getMockFunctionNamesMap().get(key); - if (mockFunctionName != null) { - String mockFunctionClassName = suite.getTestUtilityFunctions().get(mockFunctionName); - Class mockFunctionClass; - try { - mockFunctionClass = classLoader.loadClass(mockFunctionClassName); - } catch (ClassNotFoundException e) { - throw createLauncherException("failed to prepare " + mockFunctionClassName + - " for mocking reason:" + e.getMessage()); - } - for (Method method2 : mockFunctionClass.getDeclaredMethods()) { - if (method2.getName().equals(mockFunctionName)) { - if (!readFromBytes) { - classFile = replaceMethodBody(method1, method2); - readFromBytes = true; - } else { - classFile = replaceMethodBody(classFile, method1, method2); - } - } - } - } - } - } - return classFile; - } - - private static byte[] replaceMethodBody(Method method, Method mockMethod) { - Class clazz = method.getDeclaringClass(); - ClassReader cr; - try { - InputStream ins; - ins = clazz.getResourceAsStream(clazz.getSimpleName() + CLASS_EXTENSION); - cr = new ClassReader(requireNonNull(ins)); - } catch (IOException e) { - throw createLauncherException("failed to get the class reader object for the class " - + clazz.getSimpleName()); - } - ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); - ClassVisitor cv = new MockFunctionReplaceVisitor(Opcodes.ASM7, cw, method.getName(), - Type.getMethodDescriptor(method), mockMethod); - cr.accept(cv, 0); - return cw.toByteArray(); - } - - private static byte[] replaceMethodBody(byte[] classFile, Method method, Method mockMethod) { - ClassReader cr = new ClassReader(classFile); - ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); - ClassVisitor cv = new MockFunctionReplaceVisitor(Opcodes.ASM7, cw, method.getName(), - Type.getMethodDescriptor(method), mockMethod); - cr.accept(cv, 0); - return cw.toByteArray(); - } - - //Get all mocked functions in a class - private static void populateClassNameVsFunctionToMockMap(Map> classVsMockFunctionsMap, - Map mockFunctionMap) { - for (Map.Entry entry : mockFunctionMap.entrySet()) { - String key = entry.getKey(); - String functionToMockClassName; - String functionToMock; - if (key.indexOf(MOCK_LEGACY_DELIMITER) == -1) { - functionToMockClassName = key.substring(0, key.indexOf(MOCK_FN_DELIMITER)); - functionToMock = key.substring(key.indexOf(MOCK_FN_DELIMITER)); - } else if (key.indexOf(MOCK_FN_DELIMITER) == -1) { - functionToMockClassName = key.substring(0, key.indexOf(MOCK_LEGACY_DELIMITER)); - functionToMock = key.substring(key.indexOf(MOCK_LEGACY_DELIMITER)); - } else { - if (key.indexOf(MOCK_FN_DELIMITER) < key.indexOf(MOCK_LEGACY_DELIMITER)) { - functionToMockClassName = key.substring(0, key.indexOf(MOCK_FN_DELIMITER)); - functionToMock = key.substring(key.indexOf(MOCK_FN_DELIMITER)); - } else { - functionToMockClassName = key.substring(0, key.indexOf(MOCK_LEGACY_DELIMITER)); - functionToMock = key.substring(key.indexOf(MOCK_LEGACY_DELIMITER)); - } - } - functionToMock = functionToMock.replaceAll("\\\\", ""); - classVsMockFunctionsMap.computeIfAbsent(functionToMockClassName, - k -> new ArrayList<>()).add(functionToMock); - } - } - @Override public void execute(Project project) { long start = 0; @@ -360,9 +210,9 @@ public void execute(Project project) { } // If the function mocking does not exist, combine all test suite map entries - if (!isMockFunctionExist && testSuiteMapEntries.size() != 0) { + if (!isMockFunctionExist && !testSuiteMapEntries.isEmpty()) { HashMap testSuiteMap = testSuiteMapEntries.remove(0); - while (testSuiteMapEntries.size() > 0) { + while (!testSuiteMapEntries.isEmpty()) { testSuiteMap.putAll(testSuiteMapEntries.remove(0)); } testSuiteMapEntries.add(testSuiteMap); @@ -373,7 +223,7 @@ public void execute(Project project) { for (Map testSuiteMap : testSuiteMapEntries) { try { Path nativeConfigPath = target.getNativeConfigPath(); - createReflectConfig(nativeConfigPath, project.currentPackage(), testSuiteMap); + NativeUtils.createReflectConfig(nativeConfigPath, project.currentPackage(), testSuiteMap); } catch (IOException e) { throw createLauncherException("error while generating the necessary graalvm reflection config ", e); } @@ -383,7 +233,7 @@ public void execute(Project project) { TestSuite testSuite = testSuiteMap.values().toArray(new TestSuite[0])[0]; String moduleName = testSuite.getPackageID(); try { - modifyJarForFunctionMock(testSuite, target, moduleName); + NativeUtils.modifyJarForFunctionMock(testSuite, target, moduleName); } catch (IOException e) { throw createLauncherException("error occurred while running tests", e); } @@ -432,7 +282,7 @@ public void execute(Project project) { } } catch (IOException e) { TestUtils.cleanTempCache(project, cachesRoot); - throw createLauncherException("error occurred while running tests", e); + throw createLauncherException("error occurred while running tests: ", e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } @@ -464,7 +314,7 @@ private int runTestSuiteWithNativeImage(Package currentPackage, Target target, Map testSuiteMap) throws IOException, InterruptedException { String packageName = currentPackage.packageName().toString(); - String classPath = getClassPath(testSuiteMap); + String classPath = NativeUtils.getClassPath(testSuiteMap); String jacocoAgentJarPath = ""; String nativeImageCommand = System.getenv("GRAALVM_HOME"); @@ -476,9 +326,9 @@ private int runTestSuiteWithNativeImage(Package currentPackage, Target target, "https://ballerina.io/learn/build-the-executable-locally/#configure-graalvm"); } nativeImageCommand += File.separator + BIN_DIR_NAME + File.separator - + (OS.contains("win") ? "native-image.cmd" : "native-image"); + + (NativeUtils.OS.contains("win") ? "native-image.cmd" : "native-image"); - File commandExecutable = Paths.get(nativeImageCommand).toFile(); + File commandExecutable = Path.of(nativeImageCommand).toFile(); if (!commandExecutable.exists()) { throw new ProjectException("Cannot find '" + commandExecutable.getName() + "' in the GRAALVM_HOME/bin " + "directory. Install it using: gu install native-image"); @@ -504,9 +354,8 @@ private int runTestSuiteWithNativeImage(Package currentPackage, Target target, nativeArgs.addAll(Lists.of("-cp", classPath)); if (currentPackage.project().kind() == ProjectKind.SINGLE_FILE_PROJECT) { - String[] splittedArray = currentPackage.project().sourceRoot().toString(). - replace(ProjectConstants.BLANG_SOURCE_EXT, "").split("/"); - packageName = splittedArray[splittedArray.length - 1]; + packageName = currentPackage.project().sourceRoot().getFileName().toString() + .replace(ProjectConstants.BLANG_SOURCE_EXT, ""); validateResourcesWithinJar(testSuiteMap, packageName); } else if (testSuiteMap.size() == 1) { packageName = (testSuiteMap.values().toArray(new TestSuite[0])[0]).getPackageID(); @@ -514,11 +363,13 @@ private int runTestSuiteWithNativeImage(Package currentPackage, Target target, // set name and path - nativeArgs.add("-H:Name=" + addQuotationMarkToString(packageName)); - nativeArgs.add("-H:Path=" + convertWinPathToUnixFormat(addQuotationMarkToString(nativeTargetPath.toString()))); + nativeArgs.add("-H:Name=" + NativeUtils.addQuotationMarkToString(packageName)); + nativeArgs.add("-H:Path=" + NativeUtils.convertWinPathToUnixFormat(NativeUtils + .addQuotationMarkToString(nativeTargetPath.toString()))); // native-image configs - nativeArgs.add("-H:ReflectionConfigurationFiles=" + convertWinPathToUnixFormat(addQuotationMarkToString( + nativeArgs.add("-H:ReflectionConfigurationFiles=" + NativeUtils + .convertWinPathToUnixFormat(NativeUtils.addQuotationMarkToString( nativeConfigPath.resolve("reflect-config.json").toString()))); nativeArgs.add("--no-fallback"); @@ -536,8 +387,7 @@ private int runTestSuiteWithNativeImage(Package currentPackage, Target target, ProcessBuilder builder = (new ProcessBuilder()).redirectErrorStream(true); builder.command(cmdArgs.toArray(new String[0])); Process process = builder.start(); - StreamGobbler outputGobbler = - new StreamGobbler(process.getInputStream(), out); + StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream(), out); outputGobbler.start(); if (process.waitFor() == 0) { @@ -549,7 +399,10 @@ private int runTestSuiteWithNativeImage(Package currentPackage, Target target, cmdArgs.add(generatedImagePath); // Test Runner Class arguments - cmdArgs.add(target.path().toString()); // 0 + cmdArgs.add(Boolean.toString(false)); //0 + cmdArgs.add(target.path().resolve(CACHE_DIR).resolve(TESTS_CACHE_DIR_NAME) + .resolve(TESTERINA_TEST_SUITE).toString()); + cmdArgs.add(target.path().toString()); cmdArgs.add(jacocoAgentJarPath); cmdArgs.add(Boolean.toString(report)); cmdArgs.add(Boolean.toString(coverage)); @@ -557,13 +410,12 @@ private int runTestSuiteWithNativeImage(Package currentPackage, Target target, cmdArgs.add(this.disableGroupList != null ? this.disableGroupList : ""); cmdArgs.add(this.singleExecTests != null ? this.singleExecTests : ""); cmdArgs.add(Boolean.toString(isRerunTestExecution)); - cmdArgs.add(Boolean.toString(listGroups)); // 8 + cmdArgs.add(Boolean.toString(listGroups)); // 10 // 8 cmdArgs.add(Boolean.toString(isParallelExecution)); builder.command(cmdArgs.toArray(new String[0])); process = builder.start(); - outputGobbler = - new StreamGobbler(process.getInputStream(), out); + outputGobbler = new StreamGobbler(process.getInputStream(), out); outputGobbler.start(); int exitCode = process.waitFor(); outputGobbler.join(); @@ -573,18 +425,6 @@ private int runTestSuiteWithNativeImage(Package currentPackage, Target target, } } - private String addQuotationMarkToString(String word) { - return "\"" + word + "\""; - } - - private String convertWinPathToUnixFormat(String path) { - if (OS.contains("win")) { - path = path.replace("\\", "/"); - } - return path; - } - - private void validateResourcesWithinJar(Map testSuiteMap, String packageName) throws IOException { TestSuite testSuite = testSuiteMap.values().toArray(new TestSuite[0])[0]; @@ -612,152 +452,8 @@ private void validateResourcesWithinJar(Map testSuiteMap, Str } } - - private String getClassPath(Map testSuiteMap) { - List dependencies = new ArrayList<>(); - for (Map.Entry testSuiteEntry : testSuiteMap.entrySet()) { - dependencies.addAll(testSuiteEntry.getValue().getTestExecutionDependencies()); - - } - dependencies = dependencies.stream().distinct().collect(Collectors.toList()); - dependencies = dependencies.stream().map((x) -> convertWinPathToUnixFormat(addQuotationMarkToString(x))) - .collect(Collectors.toList()); - - StringJoiner classPath = new StringJoiner(File.pathSeparator); - dependencies.stream().forEach(classPath::add); - return classPath.toString(); - } - - private void modifyJarForFunctionMock(TestSuite testSuite, Target target, String moduleName) throws IOException { - String testJarName = testSuite.getOrgName() + HYPHEN + moduleName + HYPHEN + - testSuite.getVersion() + HYPHEN + TESTABLE + JAR_EXTENSION; - String testJarPath = ""; - String modifiedJarName = ""; - String mainJarPath = ""; - String mainJarName = ""; - - if (testSuite.getMockFunctionNamesMap().isEmpty()) { - return; - } - - //Add testable jar path to classloader URLs - List testExecutionDependencies = testSuite.getTestExecutionDependencies(); - List classLoaderUrlList = new ArrayList<>(); - for (String testExecutionDependency : testExecutionDependencies) { - if (testExecutionDependency.endsWith(testJarName)) { - testJarPath = testExecutionDependency; - classLoaderUrlList.add(testJarPath); - } - } - - ClassLoader classLoader = null; - - //Extract the className vs mocking functions list - Map> classVsMockFunctionsMap = new HashMap<>(); - Map mockFunctionMap = testSuite.getMockFunctionNamesMap(); - populateClassNameVsFunctionToMockMap(classVsMockFunctionsMap, mockFunctionMap); - - //Extract a mapping between classes and corresponding module jar - Map> mainJarVsClassMapping = new HashMap<>(); - for (Map.Entry> classVsMockFunctionsEntry : classVsMockFunctionsMap.entrySet()) { - String className = classVsMockFunctionsEntry.getKey(); - String[] classMetaData = className.split("\\."); - mainJarName = classMetaData[0] + HYPHEN + classMetaData[1].replace(DOT_REPLACER, DOT) + - HYPHEN + classMetaData[2]; - - if (mainJarVsClassMapping.containsKey(mainJarName)) { - mainJarVsClassMapping.get(mainJarName).add(className); - } else { - List classList = new ArrayList<>(); - classList.add(className); - mainJarVsClassMapping.put(mainJarName, classList); - } - } - - //Modify classes within module jar based on above mapping - for (Map.Entry> mainJarVsClassEntry : mainJarVsClassMapping.entrySet()) { - - mainJarName = mainJarVsClassEntry.getKey(); - modifiedJarName = mainJarName + HYPHEN + MODIFIED + JAR_EXTENSION; - - for (String testExecutionDependency : testExecutionDependencies) { - if (testExecutionDependency.contains(mainJarName) && !testExecutionDependency.contains(TESTABLE)) { - mainJarPath = testExecutionDependency; - } - } - //Add module jar path to classloader URLs - classLoaderUrlList.add(mainJarPath); - classLoader = AccessController.doPrivileged( - (PrivilegedAction) () -> new URLClassLoader(getURLList(classLoaderUrlList). - toArray(new URL[0]), ClassLoader.getSystemClassLoader())); - - //Modify classes within jar - Map modifiedClassDef = new HashMap<>(); - for (String className : mainJarVsClassEntry.getValue()) { - List functionNamesList = classVsMockFunctionsMap.get(className); - byte[] classFile = getModifiedClassBytes(className, functionNamesList, testSuite, classLoader); - modifiedClassDef.put(className, classFile); - } - - //Load all classes within module jar - Map unmodifiedFiles = loadUnmodifiedFilesWithinJar(mainJarPath); - String modifiedJarPath = (target.path().resolve(CACHE_DIR).resolve(testSuite.getOrgName()).resolve - (testSuite.getPackageName()).resolve(testSuite.getVersion()).resolve(JAVA_17_DIR)).toString() - + PATH_SEPARATOR + modifiedJarName; - //Dump modified jar - dumpJar(modifiedClassDef, unmodifiedFiles, modifiedJarPath); - - testExecutionDependencies.remove(mainJarPath); - testExecutionDependencies.add(modifiedJarPath); - } - } - - //Replace unmodified classes with corresponding modified classes and dump jar - private void dumpJar(Map modifiedClassDefs, Map unmodifiedFiles, - String modifiedJarPath) throws IOException { - List duplicatePaths = new ArrayList<>(); - try (JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(modifiedJarPath))) { - for (Map.Entry modifiedClassDef : modifiedClassDefs.entrySet()) { - if (modifiedClassDef.getValue().length > 0) { - String entry = modifiedClassDef.getKey(); - String path = entry.replaceAll("\\.", PATH_SEPARATOR) + CLASS_EXTENSION; - duplicatePaths.add(path); - jarOutputStream.putNextEntry(new ZipEntry(path)); - jarOutputStream.write(modifiedClassDefs.get(entry)); - jarOutputStream.closeEntry(); - } - } - for (Map.Entry unmodifiedFile : unmodifiedFiles.entrySet()) { - String entry = unmodifiedFile.getKey(); - if (!duplicatePaths.contains(entry)) { - jarOutputStream.putNextEntry(new ZipEntry(entry)); - jarOutputStream.write(unmodifiedFiles.get(entry)); - jarOutputStream.closeEntry(); - } - } - } - } - - private Map loadUnmodifiedFilesWithinJar(String mainJarPath) - throws IOException { - Map unmodifiedFiles = new HashMap(); - File jarFile = new File(mainJarPath); - ZipInputStream jarInputStream = new ZipInputStream(new FileInputStream(jarFile)); - ZipEntry entry; - while ((entry = jarInputStream.getNextEntry()) != null) { - String path = entry.getName(); - if (!entry.isDirectory()) { - byte[] bytes = IOUtils.toByteArray(jarInputStream); - unmodifiedFiles.put(path, bytes); - } - jarInputStream.closeEntry(); - } - jarInputStream.close(); - return unmodifiedFiles; - } - private String getGeneratedImageExtension() { - if (OS.contains("win")) { + if (NativeUtils.OS.contains("win")) { return DOT + WIN_EXEC_EXT; } return ""; diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunProfilerTask.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunProfilerTask.java index 287e30147be7..1e41192540d3 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunProfilerTask.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunProfilerTask.java @@ -28,7 +28,6 @@ import java.io.PrintStream; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.List; @@ -52,22 +51,26 @@ public class RunProfilerTask implements Task { private final PrintStream err; private static final String JAVA_OPTS = "JAVA_OPTS"; private static final String CURRENT_DIR_KEY = "current.dir"; - private static final Path TARGET_OUTPUT_PATH = Paths.get(System.getProperty(USER_DIR)); + private static final Path TARGET_OUTPUT_PATH = Path.of(System.getProperty(USER_DIR)); public RunProfilerTask(PrintStream errStream) { this.err = errStream; } private void initiateProfiler(Project project) { - String profilerSource = Paths.get(System.getProperty(BALLERINA_HOME), "bre", "lib", + String profilerSource = Path.of(System.getProperty(BALLERINA_HOME), "bre", "lib", "ballerina-profiler-1.0.jar").toString(); Path sourcePath = Path.of(profilerSource); Path targetPath = getTargetProfilerPath(project); StandardCopyOption copyOption = StandardCopyOption.REPLACE_EXISTING; + String javaOpts = System.getenv().get(JAVA_OPTS); try { Files.copy(sourcePath, targetPath, copyOption); List commands = new ArrayList<>(); commands.add(System.getProperty("java.command")); + if (javaOpts != null) { + commands.add(javaOpts.trim()); + } commands.add("-jar"); if (isInDebugMode()) { commands.add(getDebugArgs(err)); @@ -81,7 +84,9 @@ private void initiateProfiler(Project project) { commands.add(getProfileDebugArg(err)); } ProcessBuilder pb = new ProcessBuilder(commands).inheritIO(); - pb.environment().put(JAVA_OPTS, getAgentArgs()); + if (javaOpts != null) { + pb.environment().put(JAVA_OPTS, javaOpts.trim()); + } pb.environment().put(BALLERINA_HOME, System.getProperty(BALLERINA_HOME)); pb.environment().put(CURRENT_DIR_KEY, System.getProperty(USER_DIR)); pb.environment().put("java.command", System.getProperty("java.command")); @@ -108,14 +113,6 @@ public void execute(Project project) { initiateProfiler(project); } - private String getAgentArgs() { - // add jacoco agent - String jacocoArgLine = "-javaagent:" + Paths.get(System.getProperty(BALLERINA_HOME), "bre", "lib", - "jacocoagent.jar") + "=destfile=" + TARGET_OUTPUT_PATH.resolve("build").resolve("jacoco") - .resolve("test.exec"); - return jacocoArgLine + " "; - } - private Path getTargetProfilerPath(Project project) { return getProfilerPath(project).resolve("Profiler" + BLANG_COMPILED_JAR_EXT); } diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunTestsTask.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunTestsTask.java index 6b37a1459b8a..23a77a564242 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunTestsTask.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/task/RunTestsTask.java @@ -20,21 +20,16 @@ import io.ballerina.cli.utils.BuildTime; import io.ballerina.projects.JBallerinaBackend; -import io.ballerina.projects.JarLibrary; import io.ballerina.projects.JarResolver; import io.ballerina.projects.JvmTarget; import io.ballerina.projects.Module; -import io.ballerina.projects.ModuleDescriptor; -import io.ballerina.projects.ModuleId; import io.ballerina.projects.ModuleName; import io.ballerina.projects.Package; import io.ballerina.projects.PackageCompilation; -import io.ballerina.projects.PlatformLibrary; import io.ballerina.projects.Project; -import io.ballerina.projects.ProjectException; import io.ballerina.projects.ProjectKind; -import io.ballerina.projects.ResolvedPackageDependency; import io.ballerina.projects.internal.model.Target; +import io.ballerina.projects.util.ProjectConstants; import org.ballerinalang.test.runtime.entity.ModuleStatus; import org.ballerinalang.test.runtime.entity.TestReport; import org.ballerinalang.test.runtime.entity.TestSuite; @@ -43,7 +38,6 @@ import org.ballerinalang.testerina.core.TestProcessor; import org.wso2.ballerinalang.util.Lists; -import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.net.MalformedURLException; @@ -51,7 +45,6 @@ import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -59,34 +52,32 @@ import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.StringJoiner; import java.util.regex.Pattern; -import java.util.stream.Collectors; import java.util.stream.Stream; import static io.ballerina.cli.launcher.LauncherUtils.createLauncherException; import static io.ballerina.cli.utils.DebugUtils.getDebugArgs; import static io.ballerina.cli.utils.DebugUtils.isInDebugMode; +import static io.ballerina.cli.utils.TestUtils.appendRequiredArgs; import static io.ballerina.cli.utils.TestUtils.cleanTempCache; -import static io.ballerina.cli.utils.TestUtils.clearFailedTestsJson; +import static io.ballerina.cli.utils.TestUtils.createTestSuitesForProject; import static io.ballerina.cli.utils.TestUtils.generateCoverage; import static io.ballerina.cli.utils.TestUtils.generateTesterinaReports; +import static io.ballerina.cli.utils.TestUtils.getClassPath; +import static io.ballerina.cli.utils.TestUtils.getInitialCmdArgs; +import static io.ballerina.cli.utils.TestUtils.getJacocoAgentJarPath; +import static io.ballerina.cli.utils.TestUtils.getModuleJarPaths; import static io.ballerina.cli.utils.TestUtils.loadModuleStatusFromFile; import static io.ballerina.cli.utils.TestUtils.writeToTestSuiteJson; import static io.ballerina.projects.util.ProjectConstants.GENERATED_MODULES_ROOT; import static io.ballerina.projects.util.ProjectConstants.MODULES_ROOT; import static org.ballerinalang.test.runtime.util.TesterinaConstants.FULLY_QULAIFIED_MODULENAME_SEPRATOR; import static org.ballerinalang.test.runtime.util.TesterinaConstants.IGNORE_PATTERN; -import static org.ballerinalang.test.runtime.util.TesterinaConstants.MOCK_FN_DELIMITER; -import static org.ballerinalang.test.runtime.util.TesterinaConstants.MOCK_LEGACY_DELIMITER; import static org.ballerinalang.test.runtime.util.TesterinaConstants.STANDALONE_SRC_PACKAGENAME; +import static org.ballerinalang.test.runtime.util.TesterinaConstants.TESTERINA_TEST_SUITE; import static org.ballerinalang.test.runtime.util.TesterinaConstants.WILDCARD; import static org.ballerinalang.test.runtime.util.TesterinaUtils.getQualifiedClassName; -import static org.wso2.ballerinalang.compiler.util.ProjectDirConstants.BALLERINA_HOME; -import static org.wso2.ballerinalang.compiler.util.ProjectDirConstants.BALLERINA_HOME_BRE; -import static org.wso2.ballerinalang.compiler.util.ProjectDirConstants.BALLERINA_HOME_LIB; import static org.wso2.ballerinalang.compiler.util.ProjectDirConstants.BLANG_SOURCE_EXT; -import static org.wso2.ballerinalang.compiler.util.ProjectDirConstants.USER_DIR; /** * Task for executing tests. @@ -102,15 +93,13 @@ public class RunTestsTask implements Task { private String disableGroupList; private boolean report; private boolean coverage; - private String coverageReportFormat; - private boolean isRerunTestExecution; + private final String coverageReportFormat; + private final boolean isRerunTestExecution; private String singleExecTests; - private Map coverageModules; - private boolean listGroups; + private final Map coverageModules; + private final boolean listGroups; private final List cliArgs; - private final boolean isParallelExecution; - TestReport testReport; private static final Boolean isWindows = System.getProperty("os.name").toLowerCase(Locale.getDefault()) .contains("win"); @@ -152,6 +141,12 @@ public RunTestsTask(PrintStream out, PrintStream err, boolean rerunTests, String @Override public void execute(Project project) { long start = 0; + + //do not execute if cloud option is given, we only use the object to use the properties and methods in it + if (!project.buildOptions().cloud().isEmpty()) { + return; + } + if (project.buildOptions().dumpBuildTime()) { start = System.currentTimeMillis(); } @@ -180,70 +175,31 @@ public void execute(Project project) { throw createLauncherException("error while creating target directory: ", e); } - boolean hasTests = false; - PackageCompilation packageCompilation = project.currentPackage().getCompilation(); JBallerinaBackend jBallerinaBackend = JBallerinaBackend.from(packageCompilation, JvmTarget.JAVA_17); JarResolver jarResolver = jBallerinaBackend.jarResolver(); - TestProcessor testProcessor = new TestProcessor(jarResolver); - List moduleNamesList = new ArrayList<>(); - Map testSuiteMap = new HashMap<>(); - List updatedSingleExecTests; + // Only tests in packages are executed so default packages i.e. single bal files which has the package name // as "." are ignored. This is to be consistent with the "bal test" command which only executes tests // in packages. - List mockClassNames = new ArrayList<>(); - for (ModuleDescriptor moduleDescriptor : - project.currentPackage().moduleDependencyGraph().toTopologicallySortedList()) { - Module module = project.currentPackage().module(moduleDescriptor.name()); - ModuleName moduleName = module.moduleName(); + runTestsUsingSuiteJSON(project, jarResolver, target, testsCachePath, jBallerinaBackend, cachesRoot); - TestSuite suite; - try { - suite = testProcessor.testSuite(module).orElse(null); - } catch (ProjectException e) { - throw createLauncherException(e.getMessage()); - } - if (suite == null) { - continue; - } + // Cleanup temp cache for SingleFileProject + cleanTempCache(project, cachesRoot); + if (project.buildOptions().dumpBuildTime()) { + BuildTime.getInstance().testingExecutionDuration = System.currentTimeMillis() - start; + } + } - //Set 'hasTests' flag if there are any tests available in the package - if (!hasTests) { - hasTests = true; - } + private void runTestsUsingSuiteJSON(Project project, JarResolver jarResolver, Target target, Path testsCachePath, + JBallerinaBackend jBallerinaBackend, Path cachesRoot) { + TestProcessor testProcessor = new TestProcessor(jarResolver); + List moduleNamesList = new ArrayList<>(); + Map testSuiteMap = new HashMap<>(); + List mockClassNames = new ArrayList<>(); - if (!isRerunTestExecution) { - clearFailedTestsJson(target.path()); - } - if (project.kind() == ProjectKind.SINGLE_FILE_PROJECT) { - suite.setSourceFileName(project.sourceRoot().getFileName().toString()); - } - suite.setReportRequired(report || coverage); - String resolvedModuleName = - module.isDefaultModule() ? moduleName.toString() : module.moduleName().moduleNamePart(); - testSuiteMap.put(resolvedModuleName, suite); - moduleNamesList.add(resolvedModuleName); - Map mockFunctionMap = suite.getMockFunctionNamesMap(); - for (Map.Entry entry : mockFunctionMap.entrySet()) { - String key = entry.getKey(); - String functionToMockClassName; - // Find the first delimiter and compare the indexes - // The first index should always be a delimiter. Which ever one that is denotes the mocking type - if (!key.contains(MOCK_LEGACY_DELIMITER)) { - functionToMockClassName = key.substring(0, key.indexOf(MOCK_FN_DELIMITER)); - } else if (!key.contains(MOCK_FN_DELIMITER)) { - functionToMockClassName = key.substring(0, key.indexOf(MOCK_LEGACY_DELIMITER)); - } else { - if (key.indexOf(MOCK_FN_DELIMITER) < key.indexOf(MOCK_LEGACY_DELIMITER)) { - functionToMockClassName = key.substring(0, key.indexOf(MOCK_FN_DELIMITER)); - } else { - functionToMockClassName = key.substring(0, key.indexOf(MOCK_LEGACY_DELIMITER)); - } - } - mockClassNames.add(functionToMockClassName); - } - } + boolean hasTests = createTestSuitesForProject(project, target, testProcessor, testSuiteMap, moduleNamesList, + mockClassNames, this.isRerunTestExecution, this.report, this.coverage); writeToTestSuiteJson(testSuiteMap, testsCachePath); @@ -252,30 +208,10 @@ public void execute(Project project) { try { Set exclusionClassList = new HashSet<>(); testResult = runTestSuite(target, project.currentPackage(), jBallerinaBackend, mockClassNames, - exclusionClassList); - - if (report || coverage) { - for (String moduleName : moduleNamesList) { - ModuleStatus moduleStatus = loadModuleStatusFromFile( - testsCachePath.resolve(moduleName).resolve(TesterinaConstants.STATUS_FILE)); - if (moduleStatus == null) { - continue; - } - - if (!moduleName.equals(project.currentPackage().packageName().toString())) { - moduleName = ModuleName.from(project.currentPackage().packageName(), moduleName).toString(); - } - testReport.addModuleStatus(moduleName, moduleStatus); - } - try { - generateCoverage(project, testReport, jBallerinaBackend, this.includesInCoverage, - this.coverageReportFormat, this.coverageModules, exclusionClassList); - generateTesterinaReports(project, testReport, this.out, target); - } catch (IOException e) { - cleanTempCache(project, cachesRoot); - throw createLauncherException("error occurred while generating test report :", e); - } - } + exclusionClassList); + + performPostTestsTasks(project, target, testsCachePath, jBallerinaBackend, + cachesRoot, moduleNamesList, exclusionClassList); } catch (IOException | InterruptedException | ClassNotFoundException e) { cleanTempCache(project, cachesRoot); throw createLauncherException("error occurred while running tests", e); @@ -288,11 +224,33 @@ public void execute(Project project) { } else { out.println("\tNo tests found"); } + } - // Cleanup temp cache for SingleFileProject - cleanTempCache(project, cachesRoot); - if (project.buildOptions().dumpBuildTime()) { - BuildTime.getInstance().testingExecutionDuration = System.currentTimeMillis() - start; + private void performPostTestsTasks(Project project, Target target, Path testsCachePath, + JBallerinaBackend jBallerinaBackend, Path cachesRoot, + List moduleNamesList, Set exclusionClassList) + throws IOException { + if (report || coverage) { + for (String moduleName : moduleNamesList) { + ModuleStatus moduleStatus = loadModuleStatusFromFile( + testsCachePath.resolve(moduleName).resolve(TesterinaConstants.STATUS_FILE)); + if (moduleStatus == null) { + continue; + } + + if (!moduleName.equals(project.currentPackage().packageName().toString())) { + moduleName = ModuleName.from(project.currentPackage().packageName(), moduleName).toString(); + } + testReport.addModuleStatus(moduleName, moduleStatus); + } + try { + generateCoverage(project, testReport, jBallerinaBackend, this.includesInCoverage, + this.coverageReportFormat, this.coverageModules, exclusionClassList); + generateTesterinaReports(project, testReport, this.out, target); + } catch (IOException e) { + cleanTempCache(project, cachesRoot); + throw createLauncherException("error occurred while generating test report :", e); + } } } @@ -302,43 +260,17 @@ private int runTestSuite(Target target, Package currentPackage, JBallerinaBacken String packageName = currentPackage.packageName().toString(); String orgName = currentPackage.packageOrg().toString(); String classPath = getClassPath(jBallerinaBackend, currentPackage); - List cmdArgs = new ArrayList<>(); - cmdArgs.add(System.getProperty("java.command")); - cmdArgs.add("-XX:+HeapDumpOnOutOfMemoryError"); - cmdArgs.add("-XX:HeapDumpPath=" + System.getProperty(USER_DIR)); + List cmdArgs = getInitialCmdArgs(null, null); String mainClassName = TesterinaConstants.TESTERINA_LAUNCHER_CLASS_NAME; - String jacocoAgentJarPath = Paths.get(System.getProperty(BALLERINA_HOME)).resolve(BALLERINA_HOME_BRE) - .resolve(BALLERINA_HOME_LIB).resolve(TesterinaConstants.AGENT_FILE_NAME).toString(); + String jacocoAgentJarPath = getJacocoAgentJarPath(); + if (coverage) { if (!mockClassNames.isEmpty()) { - // If we have mock function we need to use jacoco offline instrumentation since jacoco doesn't - // support dynamic class file transformations while instrumenting. - List jarUrlList = getModuleJarUrlList(jBallerinaBackend, currentPackage); - Path instrumentDir = target.getTestsCachePath().resolve(TesterinaConstants.COVERAGE_DIR) - .resolve(TesterinaConstants.JACOCO_INSTRUMENTED_DIR); - JacocoInstrumentUtils.instrumentOffline(jarUrlList, instrumentDir, mockClassNames); - } - String agentCommand = "-javaagent:" - + jacocoAgentJarPath - + "=destfile=" - + target.getTestsCachePath().resolve(TesterinaConstants.COVERAGE_DIR) - .resolve(TesterinaConstants.EXEC_FILE_NAME); - if (!STANDALONE_SRC_PACKAGENAME.equals(packageName) && this.includesInCoverage == null) { - // add user defined classes for generating the jacoco exec file - agentCommand += ",includes=" + orgName + ".*"; - } else { - agentCommand += ",includes=" + this.includesInCoverage; - } - - if (!STANDALONE_SRC_PACKAGENAME.equals(packageName) && this.excludesInCoverage != null) { - if (!this.excludesInCoverage.equals("")) { - List exclusionSourceList = new ArrayList<>(List.of((this.excludesInCoverage). - split(","))); - getclassFromSourceFilePath(exclusionSourceList, currentPackage, exclusionClassList); - agentCommand += ",excludes=" + String.join(":", exclusionClassList); - } + jacocoOfflineInstrumentation(target, currentPackage, jBallerinaBackend, mockClassNames); } + String agentCommand = getAgentCommand(target, currentPackage, exclusionClassList, + jacocoAgentJarPath, packageName, orgName); cmdArgs.add(agentCommand); } @@ -350,26 +282,62 @@ private int runTestSuite(Target target, Package currentPackage, JBallerinaBacken cmdArgs.add(mainClassName); // Adds arguments to be read at the Test Runner - cmdArgs.add(target.path().toString()); - cmdArgs.add(jacocoAgentJarPath); - cmdArgs.add(Boolean.toString(report)); - cmdArgs.add(Boolean.toString(coverage)); - cmdArgs.add(this.groupList != null ? this.groupList : ""); - cmdArgs.add(this.disableGroupList != null ? this.disableGroupList : ""); - cmdArgs.add(this.singleExecTests != null ? this.singleExecTests : ""); - cmdArgs.add(Boolean.toString(isRerunTestExecution)); - cmdArgs.add(Boolean.toString(listGroups)); - cmdArgs.add(Boolean.toString(isParallelExecution)); - cmdArgs.addAll(cliArgs); + + Path testSuiteJsonPath = target.path().resolve(ProjectConstants.CACHES_DIR_NAME) + .resolve(ProjectConstants.TESTS_CACHE_DIR_NAME).resolve(TESTERINA_TEST_SUITE); + + appendRequiredArgs(cmdArgs, target.path().toString(), jacocoAgentJarPath, + testSuiteJsonPath.toString(), this.report, this.coverage, + this.groupList, this.disableGroupList, this.singleExecTests, this.isRerunTestExecution, + this.listGroups, this.cliArgs, false, isParallelExecution); ProcessBuilder processBuilder = new ProcessBuilder(cmdArgs).inheritIO(); Process proc = processBuilder.start(); return proc.waitFor(); } + public void jacocoOfflineInstrumentation(Target target, Package currentPackage, + JBallerinaBackend jBallerinaBackend, List mockClassNames) + throws IOException, ClassNotFoundException { + // If we have mock function we need to use jacoco offline instrumentation since jacoco doesn't + // support dynamic class file transformations while instrumenting. + List jarUrlList = getModuleJarUrlList(jBallerinaBackend, currentPackage); + Path instrumentDir = target.getTestsCachePath().resolve(TesterinaConstants.COVERAGE_DIR) + .resolve(TesterinaConstants.JACOCO_INSTRUMENTED_DIR); + JacocoInstrumentUtils.instrumentOffline(jarUrlList, instrumentDir, mockClassNames); + } + + public String getAgentCommand(Target target, Package currentPackage, Set exclusionClassList, + String jacocoAgentJarPath, String packageName, String orgName) throws IOException { + String agentCommand = "-javaagent:" + + jacocoAgentJarPath + + "=destfile=" + + target.getTestsCachePath().resolve(TesterinaConstants.COVERAGE_DIR) + .resolve(TesterinaConstants.EXEC_FILE_NAME); + if (!STANDALONE_SRC_PACKAGENAME.equals(packageName) && this.includesInCoverage == null) { + // add user defined classes for generating the jacoco exec file + agentCommand += ",includes=" + orgName + ".*"; + } else { + agentCommand += ",includes=" + this.includesInCoverage; + } + + if (!STANDALONE_SRC_PACKAGENAME.equals(packageName) && this.excludesInCoverage != null) { + if (!this.excludesInCoverage.isEmpty()) { + List exclusionSourceList = new ArrayList<>(List.of((this.excludesInCoverage). + split(","))); + getclassFromSourceFilePath(exclusionSourceList, currentPackage, exclusionClassList); + agentCommand += ",excludes=" + String.join(":", exclusionClassList); + } + } + return agentCommand; + } + private List getAllSourceFilePaths(String projectRootString) throws IOException { List sourceFilePaths = new ArrayList<>(); - List paths = Files.walk(Paths.get(projectRootString), 3).toList(); + List paths; + try (Stream stream = Files.walk(Path.of(projectRootString), 3)) { + paths = stream.toList(); + } if (isWindows) { projectRootString = projectRootString.replace(PATH_SEPARATOR, EXCLUDES_PATTERN_PATH_SEPARATOR); @@ -392,7 +360,7 @@ private List getAllSourceFilePaths(String projectRootString) throws IOExce private static List filterPathStream(Stream pathStream, String combinedPattern) { return pathStream.filter( FileSystems.getDefault().getPathMatcher("glob:" + combinedPattern)::matches) - .collect(Collectors.toList()); + .toList(); } private void getclassFromSourceFilePath(List sourcePatternList, Package currentPackage, @@ -417,12 +385,14 @@ private void getclassFromSourceFilePath(List sourcePatternList, Package if (sourceFile.split(Pattern.quote(PATH_SEPARATOR)).length == 2) { String moduleName = sourceFile.split(Pattern.quote(PATH_SEPARATOR))[0]; - String balFile = sourceFile.split(Pattern.quote(PATH_SEPARATOR))[1].replace(BLANG_SOURCE_EXT, ""); + String balFile = sourceFile.split(Pattern.quote(PATH_SEPARATOR))[1] + .replace(BLANG_SOURCE_EXT, ""); String className = getQualifiedClassName(org, packageName + FULLY_QULAIFIED_MODULENAME_SEPRATOR + moduleName, version, balFile); classFileList.add(className); } else if (sourceFile.split(Pattern.quote(PATH_SEPARATOR)).length == 1) { - String balFile = sourceFile.split(Pattern.quote(PATH_SEPARATOR))[0].replace(BLANG_SOURCE_EXT, ""); + String balFile = sourceFile.split(Pattern.quote(PATH_SEPARATOR))[0] + .replace(BLANG_SOURCE_EXT, ""); String className = getQualifiedClassName(org, packageName, version, balFile); classFileList.add(className); } @@ -496,60 +466,6 @@ private List extractValidSourceList(List allSourceFilePaths, List(validSourceFileSet); } - private String getClassPath(JBallerinaBackend jBallerinaBackend, Package currentPackage) { - List dependencies = new ArrayList<>(); - JarResolver jarResolver = jBallerinaBackend.jarResolver(); - - for (ModuleId moduleId : currentPackage.moduleIds()) { - Module module = currentPackage.module(moduleId); - - // Skip getting file paths for execution if module doesnt contain a testable jar - if (!module.testDocumentIds().isEmpty() || module.project().kind() - .equals(ProjectKind.SINGLE_FILE_PROJECT)) { - for (JarLibrary jarLibs : jarResolver.getJarFilePathsRequiredForTestExecution(module.moduleName())) { - dependencies.add(jarLibs.path()); - } - } - } - dependencies = dependencies.stream().distinct().collect(Collectors.toList()); - - List jarList = getModuleJarPaths(jBallerinaBackend, currentPackage); - dependencies.removeAll(jarList); - - StringJoiner classPath = new StringJoiner(File.pathSeparator); - dependencies.stream().map(Path::toString).forEach(classPath::add); - return classPath.toString(); - } - - private List getModuleJarPaths(JBallerinaBackend jBallerinaBackend, Package currentPackage) { - List moduleJarPaths = new ArrayList<>(); - - for (ModuleId moduleId : currentPackage.moduleIds()) { - Module module = currentPackage.module(moduleId); - - PlatformLibrary generatedJarLibrary = jBallerinaBackend.codeGeneratedLibrary(currentPackage.packageId(), - module.moduleName()); - moduleJarPaths.add(generatedJarLibrary.path()); - - if (!module.testDocumentIds().isEmpty()) { - PlatformLibrary codeGeneratedTestLibrary = jBallerinaBackend.codeGeneratedTestLibrary( - currentPackage.packageId(), module.moduleName()); - moduleJarPaths.add(codeGeneratedTestLibrary.path()); - } - } - - for (ResolvedPackageDependency resolvedPackageDependency : currentPackage.getResolution().allDependencies()) { - Package pkg = resolvedPackageDependency.packageInstance(); - for (ModuleId moduleId : pkg.moduleIds()) { - Module module = pkg.module(moduleId); - moduleJarPaths.add( - jBallerinaBackend.codeGeneratedLibrary(pkg.packageId(), module.moduleName()).path()); - } - } - - return moduleJarPaths.stream().distinct().collect(Collectors.toList()); - } - private List getModuleJarUrlList(JBallerinaBackend jBallerinaBackend, Package currentPackage) throws MalformedURLException { List moduleJarPaths = getModuleJarPaths(jBallerinaBackend, currentPackage); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/BrowserLauncher.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/BrowserLauncher.java index 0172fa5c59a4..04304c3eb4a5 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/BrowserLauncher.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/BrowserLauncher.java @@ -22,7 +22,7 @@ * * @since 2.0.0 */ -class BrowserLauncher { +final class BrowserLauncher { private BrowserLauncher() { } diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/BuildUtils.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/BuildUtils.java new file mode 100644 index 000000000000..a1da4720f8c8 --- /dev/null +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/BuildUtils.java @@ -0,0 +1,42 @@ +// Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com) All Rights Reserved. +// +// WSO2 Inc. 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.cli.utils; + +import io.ballerina.projects.Project; +import io.ballerina.projects.internal.model.Target; +import org.ballerinalang.compiler.plugins.CompilerPlugin; + +import java.util.ServiceLoader; + +/** + * Utilities related to creating fat jars. + * + * @since 2201.9.0 + */ + +public final class BuildUtils { + + private BuildUtils() { + } + + public static void notifyPlugins(Project project, Target target) { + ServiceLoader processorServiceLoader = ServiceLoader.load(CompilerPlugin.class); + for (CompilerPlugin plugin : processorServiceLoader) { + plugin.codeGenerated(project, target); + } + } +} diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/CentralUtils.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/CentralUtils.java index 1ff9fe897ade..87b0b1184e2b 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/CentralUtils.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/CentralUtils.java @@ -20,7 +20,6 @@ import io.ballerina.cli.launcher.LauncherUtils; import io.ballerina.projects.Settings; import org.ballerinalang.central.client.CentralAPIClient; -import org.ballerinalang.toml.exceptions.SettingsTomlException; import org.wso2.ballerinalang.util.RepoUtils; import java.io.IOException; @@ -38,7 +37,7 @@ * * @since 2.0.0 */ -public class CentralUtils { +public final class CentralUtils { private static final String BALLERINA_CENTRAL_PRODUCTION_URL = "https://central.ballerina.io"; private static final String BALLERINA_CENTRAL_STAGING_URL = "https://staging-central.ballerina.io"; @@ -51,7 +50,7 @@ private CentralUtils() { * Checks if the access token is available in Settings.toml or not. */ public static void authenticate(PrintStream errStream, String ballerinaCentralCliTokenUrl, - Path settingsTomlFilePath, CentralAPIClient client) throws SettingsTomlException { + Path settingsTomlFilePath, CentralAPIClient client) { String accessToken = client.accessToken(); if (accessToken.isEmpty()) { @@ -120,11 +119,11 @@ private static long getLastModifiedTimeOfFile(Path path) { public static String getBallerinaCentralCliTokenUrl() { if (SET_BALLERINA_STAGE_CENTRAL) { - return "https://staging-central.ballerina.io/cli-token"; + return "https://staging-central.ballerina.io/dashboard?tab=token"; } else if (SET_BALLERINA_DEV_CENTRAL) { - return "https://dev-central.ballerina.io/cli-token"; + return "https://dev-central.ballerina.io/dashboard?tab=token"; } else { - return "https://central.ballerina.io/cli-token"; + return "https://central.ballerina.io/dashboard?tab=token"; } } diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/DebugUtils.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/DebugUtils.java index 340f367a9b40..66fc823ad664 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/DebugUtils.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/DebugUtils.java @@ -10,12 +10,15 @@ * * @since 2.0.0 */ -public class DebugUtils { +public final class DebugUtils { private static final String DEBUG_ARGS_JAVA = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y"; private static final String JAVA_VERSION_PROP = "java.version"; private static final String COMPATIBLE_JRE_VERSION = "17"; + private DebugUtils() { + } + /** * Evaluates whether the ballerina program should be running on debug mode. * diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/FileUtils.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/FileUtils.java index ae9edf243b7e..552a6d71566e 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/FileUtils.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/FileUtils.java @@ -36,7 +36,11 @@ * * @since 2.0.0 */ -public class FileUtils { +public final class FileUtils { + + private FileUtils() { + } + /** * Get the name of the without the extension. * @@ -59,7 +63,7 @@ public static String getExtension(Path filePath) { if (null == fileName) { return ""; } - Optional extension = Optional.ofNullable(fileName.toString()) + Optional extension = Optional.of(fileName.toString()) .filter(f -> f.contains(".")) .map(f -> f.substring(fileName.toString().lastIndexOf(".") + 1)); return extension.orElse(""); @@ -109,11 +113,11 @@ public static String readSchema(String toolName, ClassLoader classLoader) throws StringBuilder sb = new StringBuilder(); try ( InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); - BufferedReader br = new BufferedReader(inputStreamReader); + BufferedReader br = new BufferedReader(inputStreamReader) ) { String content; while ((content = br.readLine()) != null) { - if (sb.length() > 0) { + if (!sb.isEmpty()) { sb.append('\n'); } sb.append(content); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/GraalVMCompatibilityUtils.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/GraalVMCompatibilityUtils.java index 99fa5f39ea5d..83ac291c8730 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/GraalVMCompatibilityUtils.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/GraalVMCompatibilityUtils.java @@ -35,7 +35,10 @@ * * @since 2201.7.0 */ -public class GraalVMCompatibilityUtils { +public final class GraalVMCompatibilityUtils { + + private GraalVMCompatibilityUtils() { + } private static boolean hasExternalPlatformDependencies(io.ballerina.projects.Package pkg) { // Check if external platform dependencies are defined @@ -57,6 +60,19 @@ private static String otherPlatformGraalvmCompatibleVerified(String target, } return ""; } + + private static Boolean isAllPlatformDepsGraalvmCompatible(Map platforms) { + Boolean isAllDepsGraalvmCompatible = true; + for (PackageManifest.Platform platform: platforms.values()) { + if (platform.isPlatfromDepsGraalvmCompatible() == null) { + isAllDepsGraalvmCompatible = null; + } else if (!platform.isPlatfromDepsGraalvmCompatible()) { + return false; + } + } + return isAllDepsGraalvmCompatible; + } + /** * Get the GraalVM compatibility warning message for the given package. * @@ -68,11 +84,12 @@ public static String getWarningForPackage(io.ballerina.projects.Package pkg, Str // Verify that Java dependencies (if exist) of this package are GraalVM compatible if (hasExternalPlatformDependencies(pkg)) { PackageManifest.Platform platform = pkg.manifest().platform(targetPlatform); + Boolean allDepsGraalvmCompatible = isAllPlatformDepsGraalvmCompatible(pkg.manifest().platforms()); String packageName = pkg.manifest().name().value(); if (platform == null || platform.graalvmCompatible() == null) { String graalvmCompatiblePlatform = otherPlatformGraalvmCompatibleVerified(targetPlatform, pkg.manifest().platforms()); - if (graalvmCompatiblePlatform.equals("")) { + if (graalvmCompatiblePlatform.isEmpty() && allDepsGraalvmCompatible == null) { return String.format( "************************************************************%n" + "* WARNING: Package is not verified with GraalVM. *%n" + @@ -82,11 +99,14 @@ public static String getWarningForPackage(io.ballerina.projects.Package pkg, Str "To resolve this warning, please ensure that all Java dependencies of " + "this package are compatible with GraalVM. Subsequently, update the " + "Ballerina.toml file under the section '[platform.%s]' with the " + - "attribute 'graalvmCompatible = true'.%n%n" + + "attribute 'graalvmCompatible = true'.Or, add 'graalvmCompatible = true' " + + "attribute to each Java dependency entry in Ballerina.toml.%n%n" + "************************************************************%n", packageName, targetPlatform); } else { - if (!pkg.manifest().platform(graalvmCompatiblePlatform).graalvmCompatible()) { + if ((!graalvmCompatiblePlatform.isEmpty() && + !pkg.manifest().platform(graalvmCompatiblePlatform).graalvmCompatible()) || + (allDepsGraalvmCompatible != null && !allDepsGraalvmCompatible)) { return String.format( "************************************************************%n" + "* WARNING: Package is not compatible with GraalVM. *%n" + @@ -101,7 +121,8 @@ public static String getWarningForPackage(io.ballerina.projects.Package pkg, Str packageName); } } - } else if (!platform.graalvmCompatible()) { + } else if (!platform.graalvmCompatible() || + (allDepsGraalvmCompatible != null && !allDepsGraalvmCompatible)) { return String.format( "************************************************************%n" + "* WARNING: Package is not compatible with GraalVM. *%n" + @@ -162,7 +183,7 @@ public static String getAllWarnings(io.ballerina.projects.Package pkg, String ta // List all dependencies that are not GraalVM compatible String dependencyWarning = getWarningForDependencies(pkg, isTestExec); if (dependencyWarning != null) { - if (warnings.length() > 0) { + if (!warnings.isEmpty()) { warnings.append(System.lineSeparator()); } warnings.append(dependencyWarning); diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/NativeUtils.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/NativeUtils.java index 33a56f9c2b4a..c96915ff1c5b 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/NativeUtils.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/NativeUtils.java @@ -22,13 +22,25 @@ import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import io.ballerina.projects.Package; +import io.ballerina.projects.internal.model.Target; import io.ballerina.runtime.internal.util.RuntimeUtils; +import org.apache.commons.compress.utils.IOUtils; +import org.ballerinalang.test.runtime.entity.MockFunctionReplaceVisitor; import org.ballerinalang.test.runtime.entity.TestSuite; +import org.ballerinalang.test.runtime.util.TesterinaUtils; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; import java.io.BufferedReader; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; +import java.io.InputStream; import java.io.Writer; import java.lang.reflect.Method; import java.net.MalformedURLException; @@ -38,30 +50,48 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.StringJoiner; +import java.util.jar.JarOutputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import static io.ballerina.cli.launcher.LauncherUtils.createLauncherException; import static io.ballerina.identifier.Utils.encodeNonFunctionIdentifier; import static io.ballerina.runtime.api.constants.RuntimeConstants.FILE_NAME_PERIOD_SEPARATOR; +import static java.util.Objects.requireNonNull; import static org.ballerinalang.test.runtime.util.TesterinaConstants.ANON_ORG; +import static org.ballerinalang.test.runtime.util.TesterinaConstants.CACHE_DIR; +import static org.ballerinalang.test.runtime.util.TesterinaConstants.CLASS_EXTENSION; import static org.ballerinalang.test.runtime.util.TesterinaConstants.DOT; +import static org.ballerinalang.test.runtime.util.TesterinaConstants.DOT_REPLACER; +import static org.ballerinalang.test.runtime.util.TesterinaConstants.HYPHEN; +import static org.ballerinalang.test.runtime.util.TesterinaConstants.JAR_EXTENSION; +import static org.ballerinalang.test.runtime.util.TesterinaConstants.JAVA_17_DIR; import static org.ballerinalang.test.runtime.util.TesterinaConstants.MOCK_FN_DELIMITER; +import static org.ballerinalang.test.runtime.util.TesterinaConstants.MOCK_FUNC_NAME_PREFIX; import static org.ballerinalang.test.runtime.util.TesterinaConstants.MOCK_LEGACY_DELIMITER; +import static org.ballerinalang.test.runtime.util.TesterinaConstants.MODIFIED; +import static org.ballerinalang.test.runtime.util.TesterinaConstants.PATH_SEPARATOR; +import static org.ballerinalang.test.runtime.util.TesterinaConstants.TESTABLE; /** * Utility functions and classes for test native-image generation. * * @since 2.3.0 */ -public class NativeUtils { +public final class NativeUtils { + private static final String MODULE_INIT_CLASS_NAME = "$_init"; private static final String TEST_EXEC_FUNCTION = "__execute__"; + public static final String OS = System.getProperty("os.name").toLowerCase(Locale.getDefault()); private static final ReflectConfigClassMethod REFLECTION_CONFIG_EXECUTE_METHOD = new ReflectConfigClassMethod( TEST_EXEC_FUNCTION, new String[]{"io.ballerina.runtime.internal.scheduling.Strand", @@ -78,6 +108,9 @@ public class NativeUtils { "io.ballerina.runtime.api.values.BString" }); + private NativeUtils() { + } + //Add dynamically loading classes and methods to reflection config public static void createReflectConfig(Path nativeConfigPath, Package currentPackage, Map testSuiteMap) throws IOException { @@ -138,9 +171,7 @@ public static void createReflectConfig(Path nativeConfigPath, Package currentPac if (mockedFunctionClassFile.isFile()) { BufferedReader br = Files.newBufferedReader(mockedFunctionClassPath, StandardCharsets.UTF_8); Gson gsonRead = new Gson(); - Map testFileMockedFunctionMapping = gsonRead.fromJson(br, - new TypeToken>() { - }.getType()); + Map testFileMockedFunctionMapping = gsonRead.fromJson(br, new TypeToken<>() { }); if (!testFileMockedFunctionMapping.isEmpty()) { ReflectConfigClass originalTestFileRefConfClz; for (Map.Entry testFileMockedFunctionMappingEntry : @@ -160,12 +191,12 @@ public static void createReflectConfig(Path nativeConfigPath, Package currentPac } HashSet methodSet = getMethodSet(qualifiedTestClass); originalTestFileRefConfClz = new ReflectConfigClass(qualifiedTestClassName); - for (int i = 0; i < mockedFunctions.length; i++) { - if (!methodSet.contains(mockedFunctions[i])) { + for (String mockedFunction : mockedFunctions) { + if (!methodSet.contains(mockedFunction)) { continue; } originalTestFileRefConfClz.addReflectConfigClassMethod( - new ReflectConfigClassMethod(mockedFunctions[i])); + new ReflectConfigClassMethod(mockedFunction)); originalTestFileRefConfClz.setUnsafeAllocated(true); originalTestFileRefConfClz.setAllDeclaredFields(true); originalTestFileRefConfClz.setQueryAllDeclaredMethods(true); @@ -239,7 +270,7 @@ public static List getURLList(List jarFilePaths) { for (String jarFilePath : jarFilePaths) { try { - urlList.add(Paths.get(jarFilePath).toUri().toURL()); + urlList.add(Path.of(jarFilePath).toUri().toURL()); } catch (MalformedURLException e) { // This path cannot get executed throw new RuntimeException("Failed to create classloader with all jar files", e); @@ -272,7 +303,7 @@ private static void extractMockFunctionClassMapping(Map testS functionToMock = key.substring(key.indexOf(MOCK_LEGACY_DELIMITER) + 1); } } - functionToMock = functionToMock.replaceAll("\\\\", ""); + functionToMock = functionToMock.replace("\\", ""); mockFunctionClassMapping.computeIfAbsent(functionToMockClassName, k -> new ArrayList<>()).add("$ORIG_" + functionToMock); } @@ -319,6 +350,276 @@ private static String getQualifiedClassName(String orgName, String packageName, return className; } + public static void modifyJarForFunctionMock(TestSuite testSuite, Target target, String moduleName) + throws IOException { + String testJarName = testSuite.getOrgName() + HYPHEN + moduleName + HYPHEN + + testSuite.getVersion() + HYPHEN + TESTABLE + JAR_EXTENSION; + String testJarPath = ""; + String modifiedJarName = ""; + String mainJarPath = ""; + String mainJarName = ""; + + if (testSuite.getMockFunctionNamesMap().isEmpty()) { + return; + } + + //Add testable jar path to classloader URLs + List testExecutionDependencies = testSuite.getTestExecutionDependencies(); + List classLoaderUrlList = new ArrayList<>(); + for (String testExecutionDependency : testExecutionDependencies) { + if (testExecutionDependency.endsWith(testJarName)) { + testJarPath = testExecutionDependency; + classLoaderUrlList.add(testJarPath); + } + } + + ClassLoader classLoader = null; + + //Extract the className vs mocking functions list + Map> classVsMockFunctionsMap = new HashMap<>(); + Map mockFunctionMap = testSuite.getMockFunctionNamesMap(); + populateClassNameVsFunctionToMockMap(classVsMockFunctionsMap, mockFunctionMap); + + //Extract a mapping between classes and corresponding module jar + Map> mainJarVsClassMapping = new HashMap<>(); + for (Map.Entry> classVsMockFunctionsEntry : classVsMockFunctionsMap.entrySet()) { + String className = classVsMockFunctionsEntry.getKey(); + String[] classMetaData = className.split("\\."); + mainJarName = classMetaData[0] + HYPHEN + classMetaData[1].replace(DOT_REPLACER, DOT) + + HYPHEN + classMetaData[2]; + + if (mainJarVsClassMapping.containsKey(mainJarName)) { + mainJarVsClassMapping.get(mainJarName).add(className); + } else { + List classList = new ArrayList<>(); + classList.add(className); + mainJarVsClassMapping.put(mainJarName, classList); + } + } + + //Modify classes within module jar based on above mapping + for (Map.Entry> mainJarVsClassEntry : mainJarVsClassMapping.entrySet()) { + + mainJarName = mainJarVsClassEntry.getKey(); + modifiedJarName = mainJarName + HYPHEN + MODIFIED + JAR_EXTENSION; + + for (String testExecutionDependency : testExecutionDependencies) { + if (testExecutionDependency.contains(mainJarName) && !testExecutionDependency.contains(TESTABLE)) { + mainJarPath = testExecutionDependency; + break; + } + } + //Add module jar path to classloader URLs + classLoaderUrlList.add(mainJarPath); + classLoader = AccessController.doPrivileged( + (PrivilegedAction) () -> new URLClassLoader(getURLList(classLoaderUrlList). + toArray(new URL[0]), ClassLoader.getSystemClassLoader())); + + //Modify classes within jar + Map modifiedClassDef = new HashMap<>(); + for (String className : mainJarVsClassEntry.getValue()) { + List functionNamesList = classVsMockFunctionsMap.get(className); + byte[] classFile = getModifiedClassBytes(className, functionNamesList, testSuite, classLoader); + modifiedClassDef.put(className, classFile); + } + + //Load all classes within module jar + Map unmodifiedFiles = loadUnmodifiedFilesWithinJar(mainJarPath); + String modifiedJarPath = (target.path().resolve(CACHE_DIR).resolve(testSuite.getOrgName()).resolve + (testSuite.getPackageName()).resolve(testSuite.getVersion()).resolve(JAVA_17_DIR)).toString() + + PATH_SEPARATOR + modifiedJarName; + //Dump modified jar + dumpJar(modifiedClassDef, unmodifiedFiles, modifiedJarPath); + + testExecutionDependencies.remove(mainJarPath); + testExecutionDependencies.add(modifiedJarPath); + } + } + + //Replace unmodified classes with corresponding modified classes and dump jar + private static void dumpJar(Map modifiedClassDefs, Map unmodifiedFiles, + String modifiedJarPath) throws IOException { + List duplicatePaths = new ArrayList<>(); + try (JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(modifiedJarPath))) { + for (Map.Entry modifiedClassDef : modifiedClassDefs.entrySet()) { + if (modifiedClassDef.getValue().length > 0) { + String entry = modifiedClassDef.getKey(); + String path = entry.replace(".", PATH_SEPARATOR) + CLASS_EXTENSION; + duplicatePaths.add(path); + jarOutputStream.putNextEntry(new ZipEntry(path)); + jarOutputStream.write(modifiedClassDefs.get(entry)); + jarOutputStream.closeEntry(); + } + } + for (Map.Entry unmodifiedFile : unmodifiedFiles.entrySet()) { + String entry = unmodifiedFile.getKey(); + if (!duplicatePaths.contains(entry)) { + jarOutputStream.putNextEntry(new ZipEntry(entry)); + jarOutputStream.write(unmodifiedFiles.get(entry)); + jarOutputStream.closeEntry(); + } + } + } + } + + private static Map loadUnmodifiedFilesWithinJar(String mainJarPath) + throws IOException { + Map unmodifiedFiles = new HashMap(); + File jarFile = new File(mainJarPath); + ZipInputStream jarInputStream = new ZipInputStream(new FileInputStream(jarFile)); + ZipEntry entry; + while ((entry = jarInputStream.getNextEntry()) != null) { + String path = entry.getName(); + if (!entry.isDirectory()) { + byte[] bytes = IOUtils.toByteArray(jarInputStream); + unmodifiedFiles.put(path, bytes); + } + jarInputStream.closeEntry(); + } + jarInputStream.close(); + return unmodifiedFiles; + } + + //Get all mocked functions in a class + private static void populateClassNameVsFunctionToMockMap(Map> classVsMockFunctionsMap, + Map mockFunctionMap) { + for (Map.Entry entry : mockFunctionMap.entrySet()) { + String key = entry.getKey(); + String functionToMockClassName; + String functionToMock; + if (!key.contains(MOCK_LEGACY_DELIMITER)) { + functionToMockClassName = key.substring(0, key.indexOf(MOCK_FN_DELIMITER)); + functionToMock = key.substring(key.indexOf(MOCK_FN_DELIMITER)); + } else if (!key.contains(MOCK_FN_DELIMITER)) { + functionToMockClassName = key.substring(0, key.indexOf(MOCK_LEGACY_DELIMITER)); + functionToMock = key.substring(key.indexOf(MOCK_LEGACY_DELIMITER)); + } else { + if (key.indexOf(MOCK_FN_DELIMITER) < key.indexOf(MOCK_LEGACY_DELIMITER)) { + functionToMockClassName = key.substring(0, key.indexOf(MOCK_FN_DELIMITER)); + functionToMock = key.substring(key.indexOf(MOCK_FN_DELIMITER)); + } else { + functionToMockClassName = key.substring(0, key.indexOf(MOCK_LEGACY_DELIMITER)); + functionToMock = key.substring(key.indexOf(MOCK_LEGACY_DELIMITER)); + } + } + functionToMock = functionToMock.replace("\\", ""); + classVsMockFunctionsMap.computeIfAbsent(functionToMockClassName, + k -> new ArrayList<>()).add(functionToMock); + } + } + + private static byte[] getModifiedClassBytes(String className, List functionNames, TestSuite suite, + ClassLoader classLoader) { + Class functionToMockClass; + try { + functionToMockClass = classLoader.loadClass(className); + } catch (Throwable e) { + throw createLauncherException("failed to load class: " + className); + } + + byte[] classFile = new byte[0]; + boolean readFromBytes = false; + for (Method method1 : functionToMockClass.getDeclaredMethods()) { + if (functionNames.contains(MOCK_FN_DELIMITER + method1.getName())) { + String desugaredMockFunctionName = MOCK_FUNC_NAME_PREFIX + method1.getName(); + String testClassName = TesterinaUtils.getQualifiedClassName(suite.getOrgName(), + suite.getTestPackageID(), suite.getVersion(), + suite.getPackageID().replace(DOT, FILE_NAME_PERIOD_SEPARATOR)); + Class testClass; + try { + testClass = classLoader.loadClass(testClassName); + } catch (Throwable e) { + throw createLauncherException("failed to prepare " + testClassName + " for mocking reason:" + + e.getMessage()); + } + for (Method method2 : testClass.getDeclaredMethods()) { + if (method2.getName().equals(desugaredMockFunctionName)) { + if (!readFromBytes) { + classFile = replaceMethodBody(method1, method2); + readFromBytes = true; + } else { + classFile = replaceMethodBody(classFile, method1, method2); + } + } + } + } else if (functionNames.contains(MOCK_LEGACY_DELIMITER + method1.getName())) { + String key = className + MOCK_LEGACY_DELIMITER + method1.getName(); + String mockFunctionName = suite.getMockFunctionNamesMap().get(key); + if (mockFunctionName != null) { + String mockFunctionClassName = suite.getTestUtilityFunctions().get(mockFunctionName); + Class mockFunctionClass; + try { + mockFunctionClass = classLoader.loadClass(mockFunctionClassName); + } catch (ClassNotFoundException e) { + throw createLauncherException("failed to prepare " + mockFunctionClassName + + " for mocking reason:" + e.getMessage()); + } + for (Method method2 : mockFunctionClass.getDeclaredMethods()) { + if (method2.getName().equals(mockFunctionName)) { + if (!readFromBytes) { + classFile = replaceMethodBody(method1, method2); + readFromBytes = true; + } else { + classFile = replaceMethodBody(classFile, method1, method2); + } + } + } + } + } + } + return classFile; + } + + private static byte[] replaceMethodBody(Method method, Method mockMethod) { + Class clazz = method.getDeclaringClass(); + ClassReader cr; + try (InputStream ins = clazz.getResourceAsStream(clazz.getSimpleName() + CLASS_EXTENSION)) { + cr = new ClassReader(requireNonNull(ins)); + } catch (IOException e) { + throw createLauncherException("failed to get the class reader object for the class " + + clazz.getSimpleName()); + } + ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + ClassVisitor cv = new MockFunctionReplaceVisitor(Opcodes.ASM7, cw, method.getName(), + Type.getMethodDescriptor(method), mockMethod); + cr.accept(cv, 0); + return cw.toByteArray(); + } + + private static byte[] replaceMethodBody(byte[] classFile, Method method, Method mockMethod) { + ClassReader cr = new ClassReader(classFile); + ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); + ClassVisitor cv = new MockFunctionReplaceVisitor(Opcodes.ASM7, cw, method.getName(), + Type.getMethodDescriptor(method), mockMethod); + cr.accept(cv, 0); + return cw.toByteArray(); + } + + public static String getClassPath(Map testSuiteMap) { + List dependencies = new ArrayList<>(); + for (Map.Entry testSuiteEntry : testSuiteMap.entrySet()) { + dependencies.addAll(testSuiteEntry.getValue().getTestExecutionDependencies()); + + } + dependencies = dependencies.stream().distinct() + .map((x) -> convertWinPathToUnixFormat(addQuotationMarkToString(x))).toList(); + + StringJoiner classPath = new StringJoiner(File.pathSeparator); + dependencies.forEach(classPath::add); + return classPath.toString(); + } + + public static String addQuotationMarkToString(String word) { + return "\"" + word + "\""; + } + + public static String convertWinPathToUnixFormat(String path) { + if (OS.contains("win")) { + path = path.replace("\\", "/"); + } + return path; + } + private static class ReflectConfigClass { private final String name; private List methods; @@ -403,8 +704,8 @@ public void addResourceConfigBundle(ResourceConfigBundles resourceConfigBundles) } private static class ResourceConfigBundles { - private String name; - private String[] locales; + private final String name; + private final String[] locales; private ResourceConfigBundles(String name, String[] locales) { this.name = name; diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/OsUtils.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/OsUtils.java index 8280c003cae3..5d79c8a4ee38 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/OsUtils.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/OsUtils.java @@ -23,10 +23,13 @@ * * @since 2.0.0 */ -public class OsUtils { +public final class OsUtils { private static final String OS = System.getProperty("os.name").toLowerCase(Locale.getDefault()); + private OsUtils() { + } + public static boolean isWindows() { return (OS.contains("win")); } diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/PrintUtils.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/PrintUtils.java index 54ae8cda1855..6c59d8ddabeb 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/PrintUtils.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/PrintUtils.java @@ -35,7 +35,7 @@ * * @since 2.0.0 */ -public class PrintUtils { +public final class PrintUtils { private static final PrintStream outStream = System.out; diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/ProjectWatcher.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/ProjectWatcher.java new file mode 100644 index 000000000000..d3cbd0edae6d --- /dev/null +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/ProjectWatcher.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (https://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.cli.utils; + +import io.ballerina.cli.cmd.RunCommand; +import io.ballerina.projects.ProjectKind; +import io.ballerina.projects.internal.ProjectFiles; +import io.ballerina.projects.util.FileUtils; + +import java.io.IOException; +import java.io.PrintStream; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import static io.ballerina.projects.util.ProjectConstants.BLANG_SOURCE_EXT; +import static io.ballerina.projects.util.ProjectConstants.DEPENDENCIES_TOML; +import static io.ballerina.projects.util.ProjectConstants.MODULES_ROOT; +import static io.ballerina.projects.util.ProjectConstants.RESOURCE_DIR_NAME; +import static io.ballerina.projects.util.ProjectConstants.TOML_EXTENSION; +import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; +import static java.nio.file.StandardWatchEventKinds.OVERFLOW; + +/** + * Represents a watcher that looks into project file changes. + * + * @since 2201.10.0 + */ +public class ProjectWatcher { + private final WatchService fileWatcher; + private final Map watchKeys; + private final RunCommand runCommand; + private final PrintStream outStream; + private final Path projectPath; + private final ProjectKind projectKind; + private final ScheduledExecutorService scheduledExecutorService; + private final Map debounceMap = new ConcurrentHashMap<>(); + private static final long debounceTimeMillis = 250; + private final RunCommandExecutor[] thread; + private volatile boolean forceStop = false; + + public ProjectWatcher(RunCommand runCommand, Path projectPath, PrintStream outStream) throws IOException { + this.fileWatcher = FileSystems.getDefault().newWatchService(); + this.runCommand = runCommand; + thread = new RunCommandExecutor[]{new RunCommandExecutor(runCommand, outStream)}; + this.projectPath = projectPath.toAbsolutePath(); + this.outStream = outStream; + this.watchKeys = new HashMap<>(); + this.projectKind = deriveProjectKind(); + validateProjectPath(); + this.scheduledExecutorService = Executors.newScheduledThreadPool(1); + registerFileTree(projectPath); + } + + /** + * Watches for any file changes in a Ballerina service project and restarts the service. + * Changes on source files, resources and .toml files are considered valid file changes. Changes to + * Dependencies.toml, tests, target directory and other files are ignored. + * + * @throws IOException if the watcher cannot register files for watching. + */ + public void watch() throws IOException { // TODO: find out why panics and removing service doesn't exit the code + thread[0].start(); + while (thread[0].shouldWatch() && !forceStop) { + WatchKey key; + key = fileWatcher.poll(); + Path dir = watchKeys.get(key); + if (dir == null) { + continue; + } + for (WatchEvent event : key.pollEvents()) { + WatchEvent.Kind kind = event.kind(); + if (kind == OVERFLOW) { + continue; + } + WatchEvent pathWatchEvent = cast(event); + Path changedFileName = pathWatchEvent.context(); + Path changedFilePath = dir.resolve(changedFileName).toAbsolutePath(); + if (isValidFileChange(changedFilePath)) { + long currentTime = System.currentTimeMillis(); + debounceMap.put(changedFilePath, currentTime); + scheduledExecutorService.schedule(() -> { + Long lastModifiedTime = debounceMap.get(changedFilePath); + if (lastModifiedTime == null + || (System.currentTimeMillis() - lastModifiedTime < debounceTimeMillis)) { + return; + } + outStream.println("\nDetected file changes. Re-running the project..."); + thread[0].terminate(); + waitForRunCmdThreadToJoin(); + thread[0] = new RunCommandExecutor(runCommand, outStream); + thread[0].start(); + debounceMap.remove(changedFilePath); + }, debounceTimeMillis, TimeUnit.MILLISECONDS); + } + if (kind == ENTRY_CREATE && Files.isDirectory(changedFilePath)) { + registerFileTree(changedFilePath); + } + } + boolean valid = key.reset(); + if (!valid) { + watchKeys.remove(key); + if (watchKeys.isEmpty()) { + break; + } + } + } + waitForRunCmdThreadToJoin(); + } + + public void stopWatching() { + try { + if (thread != null) { + thread[0].terminate(); + thread[0].join(); + } + forceStop = true; + fileWatcher.close(); + } catch (IOException | InterruptedException e) { + outStream.println("Error occurred while stopping the project watcher: " + e.getMessage()); + } + } + + private ProjectKind deriveProjectKind() { + return FileUtils.hasExtension(this.projectPath) ? ProjectKind.SINGLE_FILE_PROJECT : ProjectKind.BUILD_PROJECT; + } + + private boolean isValidFileChange(Path path) { + // If single file project, we only consider changes to the file itself + if (projectKind.equals(ProjectKind.SINGLE_FILE_PROJECT)) { + return projectPath.equals(path); + } + path = projectPath.relativize(path); + if (Files.isDirectory(path)) { // We ignore the directory changes + return false; + } + Path fileNamePath = path.getFileName(); + if (fileNamePath == null) { + return false; + } + String fileName = fileNamePath.toString(); + if (path.getNameCount() == 1) { + // Files (not directories) immediately in the root directory + if (fileName.endsWith(BLANG_SOURCE_EXT)) { + return true; + } + return fileName.endsWith(TOML_EXTENSION) && !fileName.equals(DEPENDENCIES_TOML); + } + if (path.startsWith(RESOURCE_DIR_NAME) && path.getNameCount() > 1) { + // name count > 1 to avoid files with resources prefix + return true; + } + if (path.startsWith(MODULES_ROOT) && path.getNameCount() > 2) { + // changes within submodules + // name count > 2 means the path is in a submodule (modules/) + Path modulePath = path.subpath(2, path.getNameCount()); + if (modulePath.getNameCount() == 1 && fileName.endsWith(BLANG_SOURCE_EXT)) { + return true; + } + return modulePath.startsWith(RESOURCE_DIR_NAME); + } + return false; + } + + private void registerFileTree(Path path) throws IOException { + if (projectKind.equals(ProjectKind.SINGLE_FILE_PROJECT)) { + Path parentPath = path.toAbsolutePath().getParent(); + if (parentPath != null) { + register(parentPath); + } + return; + } + Files.walkFileTree(path, new SimpleFileVisitor<>() { + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { + register(dir); + return FileVisitResult.CONTINUE; + } + }); + } + + private void register(Path dir) throws IOException { + WatchKey key = dir.register(fileWatcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); + watchKeys.put(key, dir); + } + + private void validateProjectPath() { + if (projectKind.equals(ProjectKind.SINGLE_FILE_PROJECT)) { + ProjectFiles.validateSingleFileProjectFilePath(projectPath); + } else { + ProjectFiles.validateBuildProjectDirPath(projectPath); + } + } + + @SuppressWarnings("unchecked") + private static WatchEvent cast(WatchEvent event) { + return (WatchEvent) event; + } + + private void waitForRunCmdThreadToJoin() { + try { + thread[0].join(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } +} diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/RunCommandExecutor.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/RunCommandExecutor.java new file mode 100644 index 000000000000..1b3644692ee0 --- /dev/null +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/RunCommandExecutor.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (https://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.cli.utils; + +import io.ballerina.cli.cmd.RunCommand; +import io.ballerina.cli.launcher.BLauncherException; +import io.ballerina.cli.launcher.LauncherUtils; +import io.ballerina.cli.launcher.RuntimePanicException; +import io.ballerina.runtime.internal.util.RuntimeUtils; +import org.ballerinalang.compiler.BLangCompilerException; + +import java.io.PrintStream; + +/** + * Represents a wrapper for the RunCommand to be run in a different thread. + * + * @since 2201.10.0 + */ +public class RunCommandExecutor extends Thread { + private static final String COMPILATION_ERROR_MESSAGE = "compilation contains errors"; + + private final RunCommand runCommand; + private final PrintStream outStream; + private volatile boolean runtimePanic; + + public RunCommandExecutor(RunCommand runCommand, PrintStream outStream) { + this.runCommand = runCommand; + this.outStream = outStream; + this.runtimePanic = false; + } + + @Override + public void run() { + // We use the original runCommand instance with the watch field set to false. That will preserve all the + // build options passed by the developer. + try { + runCommand.unsetWatch(); + runCommand.execute(); + } catch (BLangCompilerException e) { + if (!(e.getMessage().contains(COMPILATION_ERROR_MESSAGE))) { + // print the error message only if the exception was not thrown due to compilation errors + outStream.println(LauncherUtils.prepareCompilerErrorMessage(e.getMessage())); + } + // These are compiler errors, and are already logged. Hence simply exit. + } catch (BLauncherException e) { + LauncherUtils.printLauncherException(e, outStream); + } catch (RuntimePanicException ignored) { + runtimePanic = true; + } catch (Throwable e) { + RuntimeUtils.logBadSad(e); + runtimePanic = true; + } + } + + public synchronized void terminate() { + runCommand.killProcess(); + this.interrupt(); + } + + public synchronized boolean shouldWatch() { + return runCommand.containsService() && !runtimePanic; + } +} diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/TestUtils.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/TestUtils.java index 8a19467c9802..08a85132a2ed 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/TestUtils.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/TestUtils.java @@ -21,10 +21,17 @@ import com.google.gson.Gson; import io.ballerina.cli.launcher.LauncherUtils; import io.ballerina.projects.JBallerinaBackend; +import io.ballerina.projects.JarLibrary; +import io.ballerina.projects.JarResolver; import io.ballerina.projects.Module; +import io.ballerina.projects.ModuleDescriptor; import io.ballerina.projects.ModuleId; +import io.ballerina.projects.ModuleName; +import io.ballerina.projects.Package; +import io.ballerina.projects.PlatformLibrary; import io.ballerina.projects.Project; import io.ballerina.projects.ProjectKind; +import io.ballerina.projects.ResolvedPackageDependency; import io.ballerina.projects.internal.model.Target; import io.ballerina.projects.util.ProjectConstants; import io.ballerina.projects.util.ProjectUtils; @@ -35,6 +42,7 @@ import org.ballerinalang.test.runtime.entity.TestSuite; import org.ballerinalang.test.runtime.util.CodeCoverageUtils; import org.ballerinalang.test.runtime.util.TesterinaConstants; +import org.ballerinalang.testerina.core.TestProcessor; import org.jacoco.core.analysis.IClassCoverage; import org.jacoco.core.analysis.ISourceFileCoverage; import org.jacoco.core.data.ExecutionData; @@ -51,16 +59,20 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; +import java.util.StringJoiner; import static io.ballerina.cli.launcher.LauncherUtils.createLauncherException; import static org.ballerinalang.test.runtime.util.TesterinaConstants.COVERAGE_DIR; import static org.ballerinalang.test.runtime.util.TesterinaConstants.FILE_PROTOCOL; +import static org.ballerinalang.test.runtime.util.TesterinaConstants.MOCK_FN_DELIMITER; +import static org.ballerinalang.test.runtime.util.TesterinaConstants.MOCK_LEGACY_DELIMITER; import static org.ballerinalang.test.runtime.util.TesterinaConstants.REPORT_DATA_PLACEHOLDER; import static org.ballerinalang.test.runtime.util.TesterinaConstants.REPORT_ZIP_NAME; import static org.ballerinalang.test.runtime.util.TesterinaConstants.RERUN_TEST_JSON_FILE; @@ -68,14 +80,19 @@ import static org.ballerinalang.test.runtime.util.TesterinaConstants.RESULTS_JSON_FILE; import static org.ballerinalang.test.runtime.util.TesterinaConstants.TOOLS_DIR_NAME; import static org.wso2.ballerinalang.compiler.util.ProjectDirConstants.BALLERINA_HOME; +import static org.wso2.ballerinalang.compiler.util.ProjectDirConstants.BALLERINA_HOME_BRE; import static org.wso2.ballerinalang.compiler.util.ProjectDirConstants.BALLERINA_HOME_LIB; +import static org.wso2.ballerinalang.compiler.util.ProjectDirConstants.USER_DIR; /** - * Utility functions and classes for Run Test Task. + * Utility functions and classes for Run Test Task and Create Test Executable Task. * * @since 2.3.0 */ -public class TestUtils { +public final class TestUtils { + + private TestUtils() { + } public static void generateCoverage(Project project, TestReport testReport, JBallerinaBackend jBallerinaBackend, String includesInCoverage, String coverageReportFormat, @@ -91,11 +108,11 @@ public static void generateCoverage(Project project, TestReport testReport, JBal Map moduleCoverageMap = initializeCoverageMap(project); // Following lists will hold the coverage information needed for the coverage XML file generation. - List packageSourceCoverageList = new ArrayList(); - List packageNativeClassCoverageList = new ArrayList(); - List packageBalClassCoverageList = new ArrayList(); - List packageExecData = new ArrayList(); - List packageSessionInfo = new ArrayList(); + List packageSourceCoverageList = new ArrayList<>(); + List packageNativeClassCoverageList = new ArrayList<>(); + List packageBalClassCoverageList = new ArrayList<>(); + List packageExecData = new ArrayList<>(); + List packageSessionInfo = new ArrayList<>(); for (ModuleId moduleId : project.currentPackage().moduleIds()) { Module module = project.currentPackage().module(moduleId); CoverageReport coverageReport = new CoverageReport(module, moduleCoverageMap, @@ -105,9 +122,9 @@ public static void generateCoverage(Project project, TestReport testReport, JBal coverageModules.get(module.moduleName().toString()), exclusionClassList); } // Traverse coverage map and add module wise coverage to test report - for (Map.Entry mapElement : moduleCoverageMap.entrySet()) { - String moduleName = (String) mapElement.getKey(); - ModuleCoverage moduleCoverage = (ModuleCoverage) mapElement.getValue(); + for (Map.Entry mapElement : moduleCoverageMap.entrySet()) { + String moduleName = mapElement.getKey(); + ModuleCoverage moduleCoverage = mapElement.getValue(); testReport.addCoverage(moduleName, moduleCoverage); } if (CodeCoverageUtils.isRequestedReportFormat(coverageReportFormat, @@ -165,7 +182,7 @@ public static void generateTesterinaReports(Project project, TestReport testRepo testReport.finalizeTestResults(project.buildOptions().codeCoverage()); Gson gson = new Gson(); - String json = gson.toJson(testReport).replaceAll("\\\\\\(", "("); + String json = gson.toJson(testReport).replace("\\(", "("); File jsonFile = new File(reportDir.resolve(RESULTS_JSON_FILE).toString()); try (FileOutputStream fileOutputStream = new FileOutputStream(jsonFile)) { @@ -194,7 +211,7 @@ public static void generateTesterinaReports(Project project, TestReport testRepo try (Writer writer = new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8)) { writer.write(new String(content.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8)); out.println("\tView the test report at: " + - FILE_PROTOCOL + Paths.get(htmlFile.getPath()).toAbsolutePath().normalize()); + FILE_PROTOCOL + Path.of(htmlFile.getPath()).toAbsolutePath().normalize()); } } } else { @@ -213,7 +230,7 @@ public static void generateTesterinaReports(Project project, TestReport testRepo * @return path of the report tools template */ public static Path getReportToolsPath() { - return Paths.get(System.getProperty(BALLERINA_HOME)).resolve(BALLERINA_HOME_LIB). + return Path.of(System.getProperty(BALLERINA_HOME)).resolve(BALLERINA_HOME_LIB). resolve(TesterinaConstants.TOOLS_DIR_NAME).resolve(TesterinaConstants.COVERAGE_DIR). resolve(REPORT_ZIP_NAME); } @@ -247,7 +264,7 @@ public static void writeToTestSuiteJson(Map testSuiteMap, Pat } } - Path jsonFilePath = Paths.get(testsCachePath.toString(), TesterinaConstants.TESTERINA_TEST_SUITE); + Path jsonFilePath = getJsonFilePath(testsCachePath); File jsonFile = new File(jsonFilePath.toString()); try (FileOutputStream fileOutputStream = new FileOutputStream(jsonFile)) { try (Writer writer = new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8)) { @@ -262,8 +279,74 @@ public static void writeToTestSuiteJson(Map testSuiteMap, Pat } } + /** + * Create test suites for the project. + * @param project Project + * @param target Target + * @param testProcessor Test processor to create test suites + * @param testSuiteMap Test suite map that is used to store test suites + * @param moduleNamesList List of module names that will be created + * @param mockClassNames List of mock class names that will be created + * @param isRerunTestExecution Whether to rerun test execution + * @param report Whether to report + * @param coverage Whether to generate coverage + * @return Whether the project has tests + */ + public static boolean createTestSuitesForProject(Project project, Target target, TestProcessor testProcessor, + Map testSuiteMap, List moduleNamesList, + List mockClassNames, boolean isRerunTestExecution, + boolean report, boolean coverage) { + boolean hasTests = false; + for (ModuleDescriptor moduleDescriptor : + project.currentPackage().moduleDependencyGraph().toTopologicallySortedList()) { + Module module = project.currentPackage().module(moduleDescriptor.name()); + ModuleName moduleName = module.moduleName(); + + TestSuite suite = testProcessor.testSuite(module).orElse(null); + if (suite == null) { + continue; + } + + hasTests = true; + + if (!isRerunTestExecution) { + clearFailedTestsJson(target.path()); + } + if (project.kind() == ProjectKind.SINGLE_FILE_PROJECT) { + Optional sourceRootFileName = Optional.ofNullable(project.sourceRoot().getFileName()); + if (sourceRootFileName.isPresent()) { + suite.setSourceFileName(sourceRootFileName.get().toString()); + } else { + throw new IllegalStateException("Source root file name is not present"); + } + } + suite.setReportRequired(report || coverage); + String resolvedModuleName = getResolvedModuleName(module, moduleName); + testSuiteMap.put(resolvedModuleName, suite); + moduleNamesList.add(resolvedModuleName); + + addMockClasses(suite, mockClassNames); + } + return hasTests; + } + + /** + * Get the json file path for the test suite. + * @param testsCachePath Path to the tests cache + * @return Path to the json file + */ + public static Path getJsonFilePath(Path testsCachePath) { + return Path.of(testsCachePath.toString(), TesterinaConstants.TESTERINA_TEST_SUITE); + } + + public static String getJsonFilePathInFatJar(String separator) { + return ProjectConstants.CACHES_DIR_NAME + + separator + ProjectConstants.TESTS_CACHE_DIR_NAME + + separator + ProjectConstants.TEST_SUITE_JSON; + } + public static void clearFailedTestsJson(Path targetPath) { - Path rerunTestJsonPath = Paths.get(targetPath.toString(), RERUN_TEST_JSON_FILE); + Path rerunTestJsonPath = Path.of(targetPath.toString(), RERUN_TEST_JSON_FILE); if (Files.exists(rerunTestJsonPath)) { try { Files.delete(rerunTestJsonPath); @@ -278,4 +361,225 @@ public static void cleanTempCache(Project project, Path cachesRoot) { ProjectUtils.deleteDirectory(cachesRoot); } } + + /** + * Get the jacoco agent jar path. + * + * @return jacoco agent jar path + */ + public static String getJacocoAgentJarPath() { + return Path.of(System.getProperty(BALLERINA_HOME)).resolve(BALLERINA_HOME_BRE) + .resolve(BALLERINA_HOME_LIB).resolve(TesterinaConstants.AGENT_FILE_NAME).toString(); + } + + /** + * Get the initial command arguments for the test execution. + * @param javaCommand Specific java command to use + * @param userDir User directory for the out of memory heap dump + * @return List of command arguments to be used + */ + public static List getInitialCmdArgs(String javaCommand, String userDir) { + List cmdArgs = new ArrayList<>(); + + if (javaCommand == null) { + cmdArgs.add(System.getProperty("java.command")); + } else { + cmdArgs.add(javaCommand); + } + + cmdArgs.add("-XX:+HeapDumpOnOutOfMemoryError"); + + if (userDir == null) { + cmdArgs.add("-XX:HeapDumpPath=" + System.getProperty(USER_DIR)); + } else { + cmdArgs.add("-XX:HeapDumpPath=" + userDir); + } + + return cmdArgs; + } + + /** + * Append the required arguments to the command arguments list. + * @param cmdArgs List of command arguments to append to + * @param target Target + * @param jacocoAgentJarPath Jacoco agent jar path + * @param testSuiteJsonPath Test suite json path + * @param report Whether to report + * @param coverage Whether to generate coverage + * @param groupList Group list + * @param disableGroupList Disable group list + * @param singleExecTests Single execution tests + * @param isRerunTestExecution Whether to rerun test execution + * @param listGroups Whether to list groups + * @param cliArgs List of cli arguments + * @param isFatJarExecution Whether to execute from a fat jar + */ + public static void appendRequiredArgs(List cmdArgs, String target, String jacocoAgentJarPath, + String testSuiteJsonPath, boolean report, + boolean coverage, String groupList, String disableGroupList, + String singleExecTests, boolean isRerunTestExecution, + boolean listGroups, List cliArgs, boolean isFatJarExecution, + boolean isParallelExecution) { + + cmdArgs.add(Boolean.toString(isFatJarExecution)); + cmdArgs.add(testSuiteJsonPath); + cmdArgs.add(target); + cmdArgs.add(jacocoAgentJarPath); + cmdArgs.add(Boolean.toString(report)); + cmdArgs.add(Boolean.toString(coverage)); + cmdArgs.add(groupList != null ? groupList : ""); + cmdArgs.add(disableGroupList != null ? disableGroupList : ""); + cmdArgs.add(singleExecTests != null ? singleExecTests : ""); + cmdArgs.add(Boolean.toString(isRerunTestExecution)); + cmdArgs.add(Boolean.toString(listGroups)); + cmdArgs.add(Boolean.toString(isParallelExecution)); + cmdArgs.addAll(cliArgs); + } + + public static String getResolvedModuleName(Module module, ModuleName moduleName) { + return module.isDefaultModule() ? moduleName.toString() : module.moduleName().moduleNamePart(); + } + + /** + * Add the mock classes of the test suite to the list of mock class names. + * @param suite TestSuite to get the mock classes from + * @param mockClassNames List of mock class names + */ + public static void addMockClasses(TestSuite suite, List mockClassNames) { + Map mockFunctionMap = suite.getMockFunctionNamesMap(); + for (Map.Entry entry : mockFunctionMap.entrySet()) { + String key = entry.getKey(); + String functionToMockClassName; + // Find the first delimiter and compare the indexes + // The first index should always be a delimiter. Which ever one that is denotes the mocking type + functionToMockClassName = getFunctionToMockClassName(key); + mockClassNames.add(functionToMockClassName); + } + } + + private static String getFunctionToMockClassName(String id) { + String functionToMockClassName; + if (!id.contains(MOCK_LEGACY_DELIMITER)) { + functionToMockClassName = id.substring(0, id.indexOf(MOCK_FN_DELIMITER)); + } else if (!id.contains(MOCK_FN_DELIMITER)) { + functionToMockClassName = id.substring(0, id.indexOf(MOCK_LEGACY_DELIMITER)); + } else { + if (id.indexOf(MOCK_FN_DELIMITER) < id.indexOf(MOCK_LEGACY_DELIMITER)) { + functionToMockClassName = id.substring(0, id.indexOf(MOCK_FN_DELIMITER)); + } else { + functionToMockClassName = id.substring(0, id.indexOf(MOCK_LEGACY_DELIMITER)); + } + } + return functionToMockClassName; + } + + /** + * Get the classpath for the test execution. + * @param jBallerinaBackend JBallerinaBackend + * @param currentPackage Package + * @return String containing the classpath + */ + public static String getClassPath(JBallerinaBackend jBallerinaBackend, Package currentPackage) { + JarResolver jarResolver = jBallerinaBackend.jarResolver(); + Set jars = new HashSet<>(getModuleJarPaths(jBallerinaBackend, currentPackage)); + + List dependencies = getTestDependencyPaths(currentPackage, jarResolver) + .stream().filter(dependency -> !jars.contains(dependency)).toList(); + + StringJoiner classPath = joinClassPaths(dependencies); + return classPath.toString(); + } + + /** + * Join the list of paths to a single string. + * @param dependencies List of paths + * @return StringJoiner containing the joined paths + */ + public static StringJoiner joinClassPaths(List dependencies) { + StringJoiner classPath = new StringJoiner(File.pathSeparator); + dependencies.stream().map(Path::toString).forEach(classPath::add); + return classPath; + } + + /** + * Get the dependencies required for test execution. + * @param currentPackage Package + * @param jarResolver JarResolver to get the jar paths + * @return List of paths + */ + public static List getTestDependencyPaths(Package currentPackage, JarResolver jarResolver) { + List dependencies = new ArrayList<>(); + for (ModuleId moduleId : currentPackage.moduleIds()) { + Module module = currentPackage.module(moduleId); + + // Skip getting file paths for execution if module doesnt contain a testable jar + if (!module.testDocumentIds().isEmpty() || module.project().kind() + .equals(ProjectKind.SINGLE_FILE_PROJECT)) { + for (JarLibrary jarLibs : jarResolver.getJarFilePathsRequiredForTestExecution(module.moduleName())) { + dependencies.add(jarLibs.path()); + } + } + } + return dependencies.stream().distinct().toList(); + } + + /** + * Get the jar paths that should be excluded from the classpath. + * @param jBallerinaBackend JBallerinaBackend + * @param currentPackage Package + * @return List of paths to be excluded + */ + public static List getModuleJarPaths(JBallerinaBackend jBallerinaBackend, Package currentPackage) { + List moduleJarPaths = new ArrayList<>(); + + for (ModuleId moduleId : currentPackage.moduleIds()) { + Module module = currentPackage.module(moduleId); + + moduleJarPaths.addAll(getModuleJarPathsForModule(currentPackage, jBallerinaBackend, module)); + } + + for (ResolvedPackageDependency resolvedPackageDependency : currentPackage.getResolution().allDependencies()) { + Package pkg = resolvedPackageDependency.packageInstance(); + for (ModuleId moduleId : pkg.moduleIds()) { + Module module = pkg.module(moduleId); + moduleJarPaths.add( + jBallerinaBackend.codeGeneratedLibrary(pkg.packageId(), module.moduleName()).path()); + } + } + + return moduleJarPaths.stream().distinct().toList(); + } + + private static PlatformLibrary getCodeGeneratedTestLibrary(JBallerinaBackend jBallerinaBackend, + Package currentPackage, Module module) { + return jBallerinaBackend.codeGeneratedTestLibrary( + currentPackage.packageId(), module.moduleName()); + } + + private static PlatformLibrary getPlatformLibrary(JBallerinaBackend jBallerinaBackend, + Package currentPackage, Module module) { + return jBallerinaBackend.codeGeneratedLibrary(currentPackage.packageId(), + module.moduleName()); + } + + /** + * Get the excluded jar paths for a particular module. + * @param currentPackage Package + * @param jBallerinaBackend JBallerinaBackend + * @param module Module + * @return List of paths to be excluded from the classpath + */ + public static List getModuleJarPathsForModule(Package currentPackage, + JBallerinaBackend jBallerinaBackend, Module module) { + List moduleJarPaths = new ArrayList<>(); + PlatformLibrary generatedJarLibrary = getPlatformLibrary(jBallerinaBackend, currentPackage, module); + moduleJarPaths.add(generatedJarLibrary.path()); + + if (!module.testDocumentIds().isEmpty()) { + PlatformLibrary codeGeneratedTestLibrary = getCodeGeneratedTestLibrary(jBallerinaBackend, + currentPackage, module); + moduleJarPaths.add(codeGeneratedTestLibrary.path()); + } + return moduleJarPaths; + } } diff --git a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/TokenUpdater.java b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/TokenUpdater.java index 45029c9dd0c6..eb526e9ca78f 100644 --- a/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/TokenUpdater.java +++ b/cli/ballerina-cli/src/main/java/io/ballerina/cli/utils/TokenUpdater.java @@ -30,7 +30,7 @@ import java.net.HttpURLConnection; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; -import java.nio.file.Paths; +import java.nio.file.Path; import java.util.Collections; import static io.ballerina.cli.launcher.LauncherUtils.createLauncherException; @@ -41,10 +41,10 @@ * * @since 1.2.0 */ -public class TokenUpdater { +public final class TokenUpdater { - private static PrintStream errStream = System.err; - private static PrintStream outStream = System.out; + private static final PrintStream ERR_STREAM = System.err; + private static final PrintStream OUT_STREAM = System.out; private TokenUpdater() { } @@ -79,7 +79,7 @@ static class TokenUpdateHandler implements HttpHandler { public void handle(HttpExchange httpExchange) { String token = getToken(httpExchange.getRequestURI().getPath()); String currentUsersHomeDir = System.getProperty("user.home"); - String settingsTomlPath = String.valueOf(Paths.get(currentUsersHomeDir, ".ballerina", SETTINGS_FILE_NAME)); + String settingsTomlPath = String.valueOf(Path.of(currentUsersHomeDir, ".ballerina", SETTINGS_FILE_NAME)); FileOutputStream outputStream = null; try { outputStream = new FileOutputStream(settingsTomlPath); @@ -96,10 +96,10 @@ public void handle(HttpExchange httpExchange) { outputStream.close(); } } catch (IOException e) { - errStream.println("error occurred while closing the output stream: " + e.getMessage()); + ERR_STREAM.println("error occurred while closing the output stream: " + e.getMessage()); } } - outStream.println("token updated"); + OUT_STREAM.println("token updated"); OutputStream os = null; try { @@ -117,7 +117,7 @@ public void handle(HttpExchange httpExchange) { os.close(); } } catch (IOException e) { - errStream.println("error occurred while closing the output stream: " + e.getMessage()); + ERR_STREAM.println("error occurred while closing the output stream: " + e.getMessage()); } } } diff --git a/cli/ballerina-cli/src/main/java/module-info.java b/cli/ballerina-cli/src/main/java/module-info.java index 5a4dc307a549..a39930fa7717 100644 --- a/cli/ballerina-cli/src/main/java/module-info.java +++ b/cli/ballerina-cli/src/main/java/module-info.java @@ -1,7 +1,9 @@ module io.ballerina.cli { uses io.ballerina.cli.BLauncherCmd; uses io.ballerina.projects.buildtools.CodeGeneratorTool; + uses org.ballerinalang.compiler.plugins.CompilerPlugin; exports io.ballerina.cli; + exports io.ballerina.cli.task; exports io.ballerina.cli.launcher; exports io.ballerina.cli.utils; exports io.ballerina.cli.cmd; @@ -24,4 +26,5 @@ requires io.ballerina.identifier; requires org.objectweb.asm; requires org.apache.commons.io; + requires maven.resolver; } diff --git a/cli/ballerina-cli/src/main/resources/cli-help/ballerina-build.help b/cli/ballerina-cli/src/main/resources/cli-help/ballerina-build.help index ae906187f976..6c7accdc1a5a 100755 --- a/cli/ballerina-cli/src/main/resources/cli-help/ballerina-build.help +++ b/cli/ballerina-cli/src/main/resources/cli-help/ballerina-build.help @@ -63,6 +63,15 @@ OPTIONS Include the dependencies that are required to enable remote package management service. + --show-dependency-diagnostics + Print the diagnostics that are related to the dependencies. By default, these + diagnostics are not printed to the console. + + --optimize-dependency-compilation + [EXPERIMENTAL] Enables memory-efficient compilation of package dependencies + using separate processes. This can help prevent out-of-memory issues during + the initial compilation with a clean central cache. + EXAMPLES Build the current package. This will generate an 'app.jar' file in the diff --git a/cli/ballerina-cli/src/main/resources/cli-help/ballerina-doc.help b/cli/ballerina-cli/src/main/resources/cli-help/ballerina-doc.help index db9b7ea8c306..55f31f2172b2 100755 --- a/cli/ballerina-cli/src/main/resources/cli-help/ballerina-doc.help +++ b/cli/ballerina-cli/src/main/resources/cli-help/ballerina-doc.help @@ -2,7 +2,7 @@ NAME ballerina-doc - Build the documentation of a Ballerina package SYNOPSIS - bal build [OPTIONS] [] + bal doc [OPTIONS] [] DESCRIPTION @@ -30,6 +30,15 @@ OPTIONS --target-dir Target directory path. + --show-dependency-diagnostics + Print the diagnostics that are related to the dependencies. By default, these + diagnostics are not printed to the console. + + --optimize-dependency-compilation + [EXPERIMENTAL] Enables memory-efficient compilation of package dependencies + using separate processes. This can help prevent out-of-memory issues during + the initial compilation with a clean central cache. + EXAMPLES Generate API documentation for the current package. diff --git a/cli/ballerina-cli/src/main/resources/cli-help/ballerina-openapi.help b/cli/ballerina-cli/src/main/resources/cli-help/ballerina-openapi.help index 9445d0a9f0a1..de61e7e7cf49 100755 --- a/cli/ballerina-cli/src/main/resources/cli-help/ballerina-openapi.help +++ b/cli/ballerina-cli/src/main/resources/cli-help/ballerina-openapi.help @@ -13,6 +13,8 @@ SYNOPSIS [--operations ] [-n | --nullable] [--license] [--with-tests] [--client-methods] [--without-data-binding] + [--status-code-binding] [--mock] [--with-service-contract] + [--single-file] [--use-sanitized-oas] bal openapi [-i | --input] [--json] [-s | --service] @@ -21,7 +23,7 @@ DESCRIPTION Generate a Ballerina source (either a mock service or a client stub) from the given OpenAPI definition file or export an OpenAPI definition from a Ballerina service. - + The generated Ballerina sources will be written into the provided output location. @@ -80,12 +82,34 @@ OPTIONS boiler-plate for all the remote functions of the generated client. --client-methods - This option can be used in client generation to select the client method type, which can be `resource` or `remote`. (The default option is `remote`). + This option can be used in client generation to select the client + method type, which can be `resource` or `remote`. + The default option is `resource`. --without-data-binding - This option can be used in the service generation to generate a low-level service - without any data-binding logic. - + This option can be used in the service generation to generate a + low-level service without any data-binding logic. + + --status-code-binding + This option can be used in the client generation to generate the + client methods with status code response binding. + + --mock + This option can be used in the client generation to generate a mock + client for the given OpenAPI contract. + + --with-service-contract + This option can be used to generate the service contract type for the + given OpenAPI contract. + + --single-file + This option can be used to generate the Ballerina service or client + with related types and utility functions in a single file. + + --use-sanitized-oas + This is an experimental feature. This option enables service/client code + generation by modifying the given OAS to follow the Ballerina language + best practices. EXAMPLES Generate a Ballerina mock service using a `hello.yaml` OpenAPI contract. $ bal openapi -i hello.yaml --mode service @@ -110,10 +134,16 @@ EXAMPLES contract. $ bal openapi -i hello.yaml --mode service --operations operation_ID - Generate a Ballerina service without data binding using a `hello.yaml` OpenAPI contract. + Generate a Ballerina service without data binding using a `hello.yaml` + OpenAPI contract. $ bal openapi -i hello.yaml --mode service --without-data-binding $ bal openapi -i hello.yaml --without-data-binding + Generate a Ballerina client with status code response binding using a + `hello.yaml` OpenAPI contract. + $ bal openapi -i hello.yaml --mode client --status-code-binding + $ bal openapi -i hello.yaml --status-code-binding + Generate all the record fields that are not specifically mentioned as `nullable:false` in the OpenAPI schema property as nullable. $ bal openapi -i hello.yaml --nullable @@ -122,7 +152,8 @@ EXAMPLES license or copyright header. $ bal openapi -i hello.yaml --license license.txt - Generate a client with resource methods with respect to the `hello.yaml` OpenAPI contract. + Generate a client with resource methods with respect to the `hello.yaml` + OpenAPI contract. $ bal openapi -i hello.yaml --client-methods resource $ bal openapi -i hello.yaml --mode client --client-methods resource diff --git a/cli/ballerina-cli/src/main/resources/cli-help/ballerina-pack.help b/cli/ballerina-cli/src/main/resources/cli-help/ballerina-pack.help index bbfa08952135..3e1caaea194d 100644 --- a/cli/ballerina-cli/src/main/resources/cli-help/ballerina-pack.help +++ b/cli/ballerina-cli/src/main/resources/cli-help/ballerina-pack.help @@ -2,7 +2,7 @@ NAME ballerina-pack - Create distribution format of the current package SYNOPSIS - bal build [OPTIONS] [] + bal pack [OPTIONS] [] DESCRIPTION @@ -24,6 +24,15 @@ OPTIONS --target-dir Target directory path. + --show-dependency-diagnostics + Print the diagnostics that are related to the dependencies. By default, these + diagnostics are not printed to the console. + + --optimize-dependency-compilation + [EXPERIMENTAL] Enables memory-efficient compilation of package dependencies + using separate processes. This can help prevent out-of-memory issues during + the initial compilation with a clean central cache. + EXAMPLES Pack the current package into .bala file. diff --git a/cli/ballerina-cli/src/main/resources/cli-help/ballerina-profile.help b/cli/ballerina-cli/src/main/resources/cli-help/ballerina-profile.help index 8bac408ee166..1102458b4155 100755 --- a/cli/ballerina-cli/src/main/resources/cli-help/ballerina-profile.help +++ b/cli/ballerina-cli/src/main/resources/cli-help/ballerina-profile.help @@ -19,6 +19,15 @@ OPTIONS --debug Run Ballerina Profiler in the remote debugging mode. + --show-dependency-diagnostics + Print the diagnostics that are related to the dependencies. By default, these + diagnostics are not printed to the console. + + --optimize-dependency-compilation + [EXPERIMENTAL] Enables memory-efficient compilation of package dependencies + using separate processes. This can help prevent out-of-memory issues during + the initial compilation with a clean central cache. + EXAMPLES Run Ballerina profiler on the 'main' function and service(s) in the 'app.bal' file. $ bal profile app.bal diff --git a/cli/ballerina-cli/src/main/resources/cli-help/ballerina-run.help b/cli/ballerina-cli/src/main/resources/cli-help/ballerina-run.help index a56704cc24d9..73cab58bec7f 100755 --- a/cli/ballerina-cli/src/main/resources/cli-help/ballerina-run.help +++ b/cli/ballerina-cli/src/main/resources/cli-help/ballerina-run.help @@ -56,6 +56,19 @@ OPTIONS Target directory path. The directory path can be absolute or relative to the current package. + --show-dependency-diagnostics + Print the diagnostics that are related to the dependencies. By default, these + diagnostics are not printed to the console. + + --optimize-dependency-compilation + [EXPERIMENTAL] Enables memory-efficient compilation of package dependencies + using separate processes. This can help prevent out-of-memory issues during + the initial compilation with a clean central cache. + + --watch + [Experimental] Automatically re-run Ballerina service projects upon file + changes. + ARGUMENTS -- @@ -83,5 +96,5 @@ EXAMPLES add, 10, and 5. $ bal run -- add 10 5 - Run the test functions with values provided for configurable variables: + Run the 'main' function with values provided for configurable variables: $ bal run -- -Cval1=add -Cval2=10 -Cval3=5 diff --git a/cli/ballerina-cli/src/main/resources/cli-help/ballerina-test.help b/cli/ballerina-cli/src/main/resources/cli-help/ballerina-test.help index 67c6077a159c..5263042e1227 100755 --- a/cli/ballerina-cli/src/main/resources/cli-help/ballerina-test.help +++ b/cli/ballerina-cli/src/main/resources/cli-help/ballerina-test.help @@ -91,15 +91,36 @@ OPTIONS Additional build options to be passed to the GraalVM native image. --parallel - Enable parallel execution of tests. A test should satisfy the following conditions to be - executed in parallel: - - Test function should be isolated. - - If it is a data provider test, - - The data provider of a test function should be isolated. - - Test function parameters should be read-only type. - - Respective set-up, and tear-down functions (before, after, before-each, after-each, before-groups, - after-groups) of the test function should be isolated. - Parallel test execution is an experimental feature which supports only a limited set of functionality. + Enable parallel execution of tests. A test must satisfy the following + conditions to be executed in parallel: + - Test function must be isolated, either explicitly marked or inferred to be isolated. + - If a data provider is attached to a test function, + - The data provider function must be isolated. + - The types of the test function parameters must be subtypes of readonly. + - Corresponding set-up and tear-down functions of the test function must be isolated. + Parallel test execution is an experimental feature and therefore, supports only a limited + set of functionalities. + + --show-dependency-diagnostics + Print the diagnostics that are related to the dependencies. By default, these + diagnostics are not printed to the console. + + --cloud + Run the tests in a provided cloud environment. The supported cloud providers are: + - Docker + - Requires Docker to be installed on the machine. + - '--cloud=docker' can be used to run the tests in a Docker container. + If tests have resources, specify their paths in the Cloud.toml file. + - The paths to resources should be specified using the relative + path to the package. + - Use [[container.copy.files]] to specify the paths to the resources. + - target value should be added as : "/home/ballerina/". should be the + relative path to the package. + + --optimize-dependency-compilation + [EXPERIMENTAL] Enables memory-efficient compilation of package dependencies + using separate processes. This can help prevent out-of-memory issues during + the initial compilation with a clean central cache. ARGUMENTS diff --git a/cli/ballerina-cli/src/main/resources/create_cmd_templates/service/tests/service_test.bal b/cli/ballerina-cli/src/main/resources/create_cmd_templates/service/tests/service_test.bal index 0d85eb25166e..ba97e3bac6d0 100644 --- a/cli/ballerina-cli/src/main/resources/create_cmd_templates/service/tests/service_test.bal +++ b/cli/ballerina-cli/src/main/resources/create_cmd_templates/service/tests/service_test.bal @@ -5,32 +5,28 @@ import ballerina/test; http:Client testClient = check new ("http://localhost:9090"); // Before Suite Function - @test:BeforeSuite function beforeSuiteFunc() { io:println("I'm the before suite function!"); } // Test function - @test:Config {} function testServiceWithProperName() { - string|error response = testClient->get("/greeting/?name=John"); + string|error response = testClient->/greeting(name = "John"); test:assertEquals(response, "Hello, John"); } // Negative test function - @test:Config {} function testServiceWithEmptyName() returns error? { - http:Response response = check testClient->get("/greeting/"); + http:Response response = check testClient->/greeting; test:assertEquals(response.statusCode, 500); json errorPayload = check response.getJsonPayload(); test:assertEquals(errorPayload.message, "name should not be empty!"); } // After Suite Function - @test:AfterSuite function afterSuiteFunc() { io:println("I'm the after suite function!"); diff --git a/cli/ballerina-cli/src/main/resources/new_cmd_defaults/devcontainer b/cli/ballerina-cli/src/main/resources/new_cmd_defaults/devcontainer index 1f20890e3f23..1f9b23f657cd 100644 --- a/cli/ballerina-cli/src/main/resources/new_cmd_defaults/devcontainer +++ b/cli/ballerina-cli/src/main/resources/new_cmd_defaults/devcontainer @@ -1,4 +1,8 @@ { - "image": "ballerina/ballerina-devcontainer:latest", - "extensions": ["WSO2.ballerina"], -} \ No newline at end of file + "image": "ballerina/ballerina-devcontainer:latest", + "customizations": { + "vscode": { + "extensions": ["WSO2.ballerina"] + } + } +} diff --git a/cli/ballerina-cli/src/main/resources/new_cmd_defaults/gitignore b/cli/ballerina-cli/src/main/resources/new_cmd_defaults/gitignore index d5fc29aba3c3..2d54267fa809 100644 --- a/cli/ballerina-cli/src/main/resources/new_cmd_defaults/gitignore +++ b/cli/ballerina-cli/src/main/resources/new_cmd_defaults/gitignore @@ -1,4 +1,4 @@ -# Ballerina generates this directory during the compilation of a package. +# Ballerina generates this directory during the compilation of a package. # It contains compiler-generated artifacts and the final executable if this is an application package. target/ diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/AddCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/AddCommandTest.java index be8e7c04670c..b3b01d39e7fa 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/AddCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/AddCommandTest.java @@ -38,6 +38,7 @@ public class AddCommandTest extends BaseCommandTest { private Path projectPath; private Path modulesPath; + @Override @BeforeClass public void setup() throws IOException { super.setup(); diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BaseCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BaseCommandTest.java index 070e76fe5f3e..8f28489847f9 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BaseCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BaseCommandTest.java @@ -28,14 +28,15 @@ import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import java.util.stream.Stream; import static io.ballerina.projects.util.ProjectConstants.CENTRAL_REPOSITORY_CACHE_NAME; @@ -55,7 +56,7 @@ public abstract class BaseCommandTest { public void setup() throws IOException { System.setProperty("java.command", "java"); this.tmpDir = Files.createTempDirectory("b7a-cmd-test-" + System.nanoTime()); - this.homeCache = Paths.get("build", "userHome"); + this.homeCache = Path.of("build", "userHome"); this.console = new ByteArrayOutputStream(); this.printStream = new PrintStream(this.console); } @@ -66,23 +67,34 @@ public void beforeMethod() { this.printStream = new PrintStream(this.console); } + @DataProvider(name = "optimizeDependencyCompilation") + public Object [] [] provideOptimizeDependencyCompilation() { + return new Object [][] {{ false }, { true }}; + } + protected String readOutput() throws IOException { return readOutput(false); } protected String readOutput(boolean silent) throws IOException { + return readOutput(silent, true); + } + + protected String readOutput(boolean silent, boolean closeConsole) throws IOException { String output = ""; output = console.toString(); - console.close(); - console = new ByteArrayOutputStream(); - printStream = new PrintStream(console); + if (closeConsole) { + console.close(); + console = new ByteArrayOutputStream(); + printStream = new PrintStream(console); + } if (!silent) { PrintStream out = System.out; out.println(output); } return output; } - + /** * Execute a command and get the exception. * @@ -114,9 +126,9 @@ protected void cacheBalaToCentralRepository(Path balaProjectDirectory, String or Path balaDestPath = centralRepoPath.resolve(org).resolve(name).resolve(version).resolve(platform); Files.createDirectories(balaDestPath); - try { - Files.walk(balaProjectDirectory).forEach(a -> { - Path b = Paths.get(String.valueOf(balaDestPath), + try (Stream files = Files.walk(balaProjectDirectory)) { + files.forEach(a -> { + Path b = Path.of(String.valueOf(balaDestPath), a.toString().substring(balaProjectDirectory.toString().length())); try { if (!a.toString().equals(String.valueOf(balaProjectDirectory))) { diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BuildCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BuildCommandTest.java index ce663ee60b46..331812a62539 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BuildCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BuildCommandTest.java @@ -24,8 +24,11 @@ import io.ballerina.projects.SemanticVersion; import io.ballerina.projects.environment.Environment; import io.ballerina.projects.environment.EnvironmentBuilder; +import io.ballerina.projects.util.BuildToolUtils; import io.ballerina.projects.util.ProjectUtils; import org.ballerinalang.test.BCompileUtil; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeGroups; @@ -41,10 +44,10 @@ import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; +import java.util.List; import java.util.Objects; import java.util.jar.JarFile; @@ -64,12 +67,13 @@ */ public class BuildCommandTest extends BaseCommandTest { private Path testResources; - private static final Path testBuildDirectory = Paths.get("build").toAbsolutePath(); + private static final Path testBuildDirectory = Path.of("build").toAbsolutePath(); private static final Path testDistCacheDirectory = testBuildDirectory.resolve(DIST_CACHE_DIRECTORY); - Path customUserHome = Paths.get("build", "user-home"); + Path customUserHome = Path.of("build", "user-home"); Environment environment = EnvironmentBuilder.getBuilder().setUserHome(customUserHome).build(); ProjectEnvironmentBuilder projectEnvironmentBuilder = ProjectEnvironmentBuilder.getBuilder(environment); + @Override @BeforeClass public void setup() throws IOException { super.setup(); @@ -77,7 +81,7 @@ public void setup() throws IOException { this.testResources = super.tmpDir.resolve("build-test-resources"); URI testResourcesURI = Objects.requireNonNull( getClass().getClassLoader().getResource("test-resources")).toURI(); - Files.walkFileTree(Paths.get(testResourcesURI), new BuildCommandTest.Copy(Paths.get(testResourcesURI), + Files.walkFileTree(Path.of(testResourcesURI), new BuildCommandTest.Copy(Path.of(testResourcesURI), this.testResources)); } catch (URISyntaxException e) { Assert.fail("error loading resources"); @@ -89,19 +93,20 @@ public void setup() throws IOException { Files.copy(validProjectPath, this.testResources.resolve("validProject-no-permission")); } - @Test(description = "Build a valid ballerina file") - public void testBuildBalFile() throws IOException { + @Test(description = "Build a valid ballerina file", dataProvider = "optimizeDependencyCompilation") + public void testBuildBalFile(Boolean optimizeDependencyCompilation) throws IOException { Path validBalFilePath = this.testResources.resolve("valid-bal-file").resolve("hello_world.bal"); System.setProperty(USER_DIR_PROPERTY, this.testResources.resolve("valid-bal-file").toString()); // set valid source root - BuildCommand buildCommand = new BuildCommand(validBalFilePath, printStream, printStream, false); + BuildCommand buildCommand = new BuildCommand(validBalFilePath, printStream, printStream, false, + optimizeDependencyCompilation); // name of the file as argument new CommandLine(buildCommand).parseArgs(validBalFilePath.toString()); buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-hello-world-bal.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-hello-world-bal.txt")); Assert.assertTrue(Files.exists(this.testResources .resolve("valid-bal-file") @@ -110,7 +115,8 @@ public void testBuildBalFile() throws IOException { // copying the executable to a different location before deleting // to use for testCodeGeneratorForSingleFile test case Files.copy(this.testResources.resolve("valid-bal-file").resolve("hello_world.jar"), - this.testResources.resolve("valid-bal-file").resolve("hello_world-for-codegen-test.jar")); + this.testResources.resolve("valid-bal-file").resolve("hello_world-for-codegen-test.jar"), + StandardCopyOption.REPLACE_EXISTING); Files.delete(this.testResources .resolve("valid-bal-file") @@ -129,7 +135,7 @@ public void testBuildBalFileWithOutputFlag() throws IOException { buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-foo-bal.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-foo-bal.txt")); Assert.assertTrue(Files.exists(this.testResources.resolve("valid-bal-file").resolve("foo.jar"))); long executableSize = Files.size(this.testResources.resolve("valid-bal-file").resolve("foo.jar")); @@ -141,7 +147,7 @@ public void testBuildBalFileWithOutputFlag() throws IOException { buildCommand.execute(); buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-bar-bal.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-bar-bal.txt")); Assert.assertTrue(Files.exists(this.testResources.resolve("valid-bal-file").resolve("bar.jar"))); Assert.assertEquals(Files.size(this.testResources.resolve("valid-bal-file").resolve("bar.jar")), @@ -160,7 +166,7 @@ public void testBuildBalFileWithOutputFlag() throws IOException { String helloWorldJarLog = getOutput("build-bal-with-absolute-jar-path.txt") .replace("", helloExecutableTmpDir.toAbsolutePath().resolve("hello_world.jar").toString()); - Assert.assertEquals(buildLog.replaceAll("\r", ""), helloWorldJarLog); + Assert.assertEquals(buildLog.replace("\r", ""), helloWorldJarLog); Assert.assertTrue(Files.exists(helloExecutableTmpDir.toAbsolutePath().resolve("hello_world.jar"))); @@ -176,7 +182,7 @@ public void testBuildBalFileWithOutputFlag() throws IOException { String hippoJarLog = getOutput("build-bal-with-absolute-jar-path.txt") .replace("", helloExecutableTmpDir.toAbsolutePath().resolve("hippo.jar").toString()); - Assert.assertEquals(buildLog.replaceAll("\r", ""), hippoJarLog); + Assert.assertEquals(buildLog.replace("\r", ""), hippoJarLog); Assert.assertTrue(Files.exists(helloExecutableTmpDir.toAbsolutePath().resolve("hippo.jar"))); ProjectUtils.deleteDirectory(helloExecutableTmpDir); @@ -190,7 +196,7 @@ public void testNonBalFileBuild() throws IOException { buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertTrue(buildLog.replaceAll("\r", "") + Assert.assertTrue(buildLog.replace("\r", "") .contains("Invalid Ballerina source file(.bal): " + nonBalFilePath)); } @@ -203,7 +209,7 @@ public void testNonExistingBalFile() throws IOException { new CommandLine(buildCommand).parseArgs(validBalFilePath.toString()); buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertTrue(buildLog.replaceAll("\r", "") + Assert.assertTrue(buildLog.replace("\r", "") .contains("The file does not exist: " + validBalFilePath)); } @@ -222,49 +228,51 @@ public void testBuildBalFileWithNoEntry() { } } - @Test(description = "Build bal file containing syntax error") - public void testBalFileWithSyntaxError() throws IOException { + @Test(description = "Build bal file containing syntax error", dataProvider = "optimizeDependencyCompilation") + public void testBalFileWithSyntaxError(Boolean optimizeDependencyCompilation) throws IOException { // valid source root path Path balFilePath = this.testResources.resolve("bal-file-with-syntax-error").resolve("hello_world.bal"); - BuildCommand buildCommand = new BuildCommand(balFilePath, printStream, printStream, false); + BuildCommand buildCommand = new BuildCommand(balFilePath, printStream, printStream, false, + optimizeDependencyCompilation); // non existing bal file new CommandLine(buildCommand).parseArgs(balFilePath.toString()); try { buildCommand.execute(); } catch (BLauncherException e) { String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-syntax-err-bal.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-syntax-err-bal.txt")); Assert.assertTrue(e.getDetailedMessages().get(0).contains("compilation contains errors")); } } - @Test(description = "Build bal package containing syntax error") - public void testBalProjectWithSyntaxError() throws IOException { + @Test(description = "Build bal package containing syntax error", dataProvider = "optimizeDependencyCompilation") + public void testBalProjectWithSyntaxError(Boolean optimizeDependencyCompilation) throws IOException { // valid source root path Path balFilePath = this.testResources.resolve("bal-project-with-syntax-error"); - BuildCommand buildCommand = new BuildCommand(balFilePath, printStream, printStream, false, true); + BuildCommand buildCommand = new BuildCommand(balFilePath, printStream, printStream, false, + optimizeDependencyCompilation); // non existing bal file new CommandLine(buildCommand).parseArgs(balFilePath.toString()); try { buildCommand.execute(); } catch (BLauncherException e) { String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-syntax-err-package.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-syntax-err-package.txt")); Assert.assertTrue(e.getDetailedMessages().get(0).contains("compilation contains errors")); } } - - @Test(description = "Build a valid ballerina project") - public void testBuildBalProject() throws IOException { + @Test(description = "Build a valid ballerina project", dataProvider = "optimizeDependencyCompilation") + public void testBuildBalProject(Boolean optimizeDependencyCompilation) throws IOException { Path projectPath = this.testResources.resolve("validApplicationProject"); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, + optimizeDependencyCompilation); // non existing bal file new CommandLine(buildCommand).parseArgs(); buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-bal-project.txt")); Assert.assertTrue(projectPath.resolve("target").resolve("bin").resolve("winery.jar").toFile().exists()); @@ -277,11 +285,8 @@ public void testBuildBalProject() throws IOException { public void testCodeGeneratorForSingleFile() throws IOException { Path execPath = this.testResources.resolve("valid-bal-file").resolve("hello_world-for-codegen-test.jar"); String generatedSource = "dummyfunc-generated_1.class"; - String generatedResource = "resources/$anon/./0/openapi-spec.yaml"; - try (JarFile execJar = new JarFile(execPath.toString())) { Assert.assertNull(execJar.getJarEntry(generatedSource)); - Assert.assertNotNull(execJar.getJarEntry(generatedResource)); } } @@ -293,22 +298,17 @@ public void testCodeGeneratorForBuildProject() throws IOException { .resolve("foo-winery-0.1.0.jar"); Path execPath = projectPath.resolve("target").resolve("bin").resolve("winery.jar"); String generatedSource = "foo/winery/0/dummyfunc-generated_1.class"; - String generatedResource = "resources/foo/winery/0/openapi-spec.yaml"; - try (JarFile thinJar = new JarFile(thinJarPath.toString())) { Assert.assertNotNull(thinJar.getJarEntry(generatedSource)); - Assert.assertNotNull(thinJar.getJarEntry(generatedResource)); } - try (JarFile execJar = new JarFile(execPath.toString())) { Assert.assertNotNull(execJar.getJarEntry(generatedSource)); - Assert.assertNotNull(execJar.getJarEntry(generatedResource)); } } /** * Test jar conflicts of platform libs. - * + *
      * one-1.0.0.jar
      * .
      * ├── META-INF
@@ -345,6 +345,7 @@ public void testCodeGeneratorForBuildProject() throws IOException {
      *         ├── Sample2.class ---> conflicted class file
      *         ├── Sample3.class ---> conflicted class file
      *         └── Sample4.class ---> conflicted class file
+     * 
*/ @Test(description = "Build a ballerina project with conflicted jars") public void testBuildBalProjectWithJarConflicts() throws IOException { @@ -355,7 +356,7 @@ public void testBuildBalProjectWithJarConflicts() throws IOException { buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-bal-project-with-jar-conflicts.txt")); Assert.assertTrue( @@ -365,11 +366,13 @@ public void testBuildBalProjectWithJarConflicts() throws IOException { .resolve("pramodya-conflictProject-0.1.7.jar").toFile().exists()); } - @Test(description = "Build a ballerina project with provided scope platform jars") - public void testBuildProjectWithProvidedJars() { + @Test(description = "Build a ballerina project with provided scope platform jars", + dataProvider = "optimizeDependencyCompilation") + public void testBuildProjectWithProvidedJars(Boolean optimizeDependencyCompilation) { Path projectPath = this.testResources.resolve("projectWithProvidedScope"); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, + optimizeDependencyCompilation); new CommandLine(buildCommand).parseArgs(); try { buildCommand.execute(); @@ -389,20 +392,21 @@ public void testBuildProjectWithProvidedWarning() throws IOException { buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("project-with-provided-warning.txt")); } - @Test(description = "Build a valid ballerina project with java imports") - public void testBuildJavaBalProject() throws IOException { + @Test(description = "Build a valid ballerina project with java imports", + dataProvider = "optimizeDependencyCompilation") + public void testBuildJavaBalProject(Boolean optimizeDependencyCompilation) throws IOException { Path projectPath = this.testResources.resolve("validJavaProject"); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); - // non existing bal file + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, + optimizeDependencyCompilation); new CommandLine(buildCommand).parseArgs(); buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-bal-project.txt")); Assert.assertTrue(projectPath.resolve("target").resolve("bin").resolve("winery.jar").toFile().exists()); @@ -411,15 +415,15 @@ public void testBuildJavaBalProject() throws IOException { .resolve("foo-winery-0.1.0.jar").toFile().exists()); } - @Test(description = "Build a valid ballerina project") - public void testBuildBalProjectFromADifferentDirectory() throws IOException { + @Test(dataProvider = "optimizeDependencyCompilation") + public void testBuildBalProjectFromADifferentDirectory(Boolean optimizeDependencyCompilation) throws IOException { Path projectPath = this.testResources.resolve("validApplicationProject"); - BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); - // non existing bal file + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, + optimizeDependencyCompilation); new CommandLine(buildCommand).parseArgs(projectPath.toString()); buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-bal-project.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-bal-project.txt")); Assert.assertTrue(projectPath.resolve("target").resolve("bin").resolve("winery.jar").toFile().exists()); Assert.assertTrue(projectPath.resolve("target").resolve("cache").resolve("foo") @@ -427,16 +431,16 @@ public void testBuildBalProjectFromADifferentDirectory() throws IOException { .resolve("foo-winery-0.1.0.jar").toFile().exists()); } - @Test(description = "Build a valid ballerina project") - public void testBuildProjectWithTests() throws IOException { + @Test(dataProvider = "optimizeDependencyCompilation") + public void testBuildProjectWithTests(Boolean optimizeDependencyCompilation) throws IOException { Path projectPath = this.testResources.resolve("validProjectWithTests"); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); - // non existing bal file + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, + optimizeDependencyCompilation); new CommandLine(buildCommand).parseArgs(); buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-bal-project-with-tests.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-bal-project-with-tests.txt")); Assert.assertTrue(projectPath.resolve("target").resolve("bin").resolve("winery.jar").toFile().exists()); Assert.assertTrue(projectPath.resolve("target").resolve("cache").resolve("foo") @@ -444,19 +448,19 @@ public void testBuildProjectWithTests() throws IOException { .resolve("foo-winery-0.1.0.jar").toFile().exists()); } - @Test(description = "Build a valid ballerina project") - public void testBuildMultiModuleProject() throws IOException { + @Test(dataProvider = "optimizeDependencyCompilation") + public void testBuildMultiModuleProject(Boolean optimizeDependencyCompilation) throws IOException { Path projectPath = this.testResources.resolve("validMultiModuleProject"); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); - // non existing bal file + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, + optimizeDependencyCompilation); new CommandLine(buildCommand).parseArgs(); buildCommand.execute(); String buildLog = readOutput(true); String actualOutput1 = getOutput("build-multi-module-project-winery.txt"); String actualOutput2 = getOutput("build-multi-module-project-winery-storage.txt"); - Assert.assertTrue(buildLog.replaceAll("\r", "").equals(actualOutput1) - || buildLog.replaceAll("\r", "").equals(actualOutput2)); + Assert.assertTrue(buildLog.replace("\r", "").equals(actualOutput1) + || buildLog.replace("\r", "").equals(actualOutput2)); Assert.assertTrue(projectPath.resolve("target").resolve("bin").resolve("winery.jar").toFile().exists()); Assert.assertTrue(projectPath.resolve("target").resolve("cache").resolve("foo") @@ -473,11 +477,10 @@ public void testBuildProjectWithDefaultBuildOptions() throws IOException { Path projectPath = this.testResources.resolve("validProjectWithBuildOptions"); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); - // non existing bal file new CommandLine(buildCommand).parseArgs(); buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-project-default-build-options.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-project-default-build-options.txt")); Assert.assertTrue(projectPath.resolve("target").resolve("bin").resolve("winery.jar").toFile().exists()); Assert.assertTrue(projectPath.resolve("target").resolve("cache").resolve("foo") @@ -494,7 +497,6 @@ public void testBuildProjectOverrideBuildOptions() throws IOException { System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); BuildCommand buildCommand = new BuildCommand( projectPath, printStream, printStream, false); - // non existing bal file new CommandLine(buildCommand).parseArgs(); try { buildCommand.execute(); @@ -505,7 +507,7 @@ public void testBuildProjectOverrideBuildOptions() throws IOException { String expectedLog = getOutput("build-bal-project-override-build-options.txt") .replace("", projectPath.resolve("target").resolve("report").resolve("test_results.json").toString()); - Assert.assertEquals(buildLog.replaceAll("\r", ""), expectedLog); + Assert.assertEquals(buildLog.replace("\r", ""), expectedLog); Assert.assertTrue(projectPath.resolve("target").resolve("bin").resolve("winery.jar").toFile().exists()); Assert.assertTrue(projectPath.resolve("target").resolve("cache").resolve("foo") @@ -525,7 +527,6 @@ public void testSingleFileWithDefaultBuildOptions() throws IOException { System.setProperty(USER_DIR_PROPERTY, this.testResources.resolve("valid-bal-file").toString()); BuildCommand buildCommand = new BuildCommand( projectPath, printStream, printStream, false); - // non existing bal file new CommandLine(buildCommand).parseArgs(); try { buildCommand.execute(); @@ -533,7 +534,7 @@ public void testSingleFileWithDefaultBuildOptions() throws IOException { Assert.fail(e.getDetailedMessages().get(0)); } String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-hello-world-bal.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-hello-world-bal.txt")); Assert.assertTrue(Files.exists(this.testResources .resolve("valid-bal-file") @@ -549,8 +550,7 @@ public void testSingleFileOverrideBuildOptions() throws IOException { Path projectPath = this.testResources.resolve("valid-bal-file").resolve("hello_world.bal"); System.setProperty(USER_DIR_PROPERTY, this.testResources.resolve("valid-bal-file").toString()); BuildCommand buildCommand = new BuildCommand( - projectPath, printStream, printStream, false); - // non existing bal file + projectPath, printStream, printStream, false, Boolean.TRUE); new CommandLine(buildCommand).parseArgs(); try { buildCommand.execute(); @@ -558,7 +558,7 @@ public void testSingleFileOverrideBuildOptions() throws IOException { Assert.fail(e.getDetailedMessages().get(0)); } String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-hello-world-bal-with-build-options.txt")); Assert.assertTrue(Files.exists(this.testResources.resolve("valid-bal-file").resolve("hello_world.jar"))); @@ -613,7 +613,7 @@ public void testBuildProjectWithEmptyBallerinaToml() throws IOException { new CommandLine(buildCommand).parseArgs(); buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-project-with-empty-ballerina-toml.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-project-with-empty-ballerina-toml.txt")); Assert.assertTrue( projectPath.resolve("target").resolve("bin").resolve("validProjectWithEmptyBallerinaToml.jar").toFile() @@ -627,24 +627,47 @@ public void testBuildEmptyProjectWithCompilerPlugin() throws IOException { BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); new CommandLine(buildCommand).parseArgs(); - buildCommand.execute(); - String buildLog = readOutput(true); + try { + buildCommand.execute(); + } catch (BLauncherException e) { + List messages = e.getMessages(); + Assert.assertEquals(messages.size(), 1); + Assert.assertEquals(messages.get(0), getOutput("build-empty-project-with-compiler-plugin.txt")); + } + } - Assert.assertEquals(buildLog.replaceAll("\r", ""), - getOutput("build-empty-project-with-compiler-plugin.txt")); + @Test(description = "Build an empty package with code generator build tools") + public void testBuildEmptyProjectWithBuildTools() throws IOException { + BCompileUtil.compileAndCacheBala(testResources.resolve("buildToolResources").resolve("tools") + .resolve("ballerina-generate-file").toString(), testDistCacheDirectory, projectEnvironmentBuilder); + Path projectPath = this.testResources.resolve("emptyProjectWithBuildTool"); + replaceDependenciesTomlContent(projectPath, "**INSERT_DISTRIBUTION_VERSION_HERE**", + RepoUtils.getBallerinaShortVersion()); + System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); + try (MockedStatic repoUtils = Mockito.mockStatic( + BuildToolUtils.class, Mockito.CALLS_REAL_METHODS)) { + repoUtils.when(BuildToolUtils::getCentralBalaDirPath).thenReturn(testDistCacheDirectory.resolve("bala")); + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); + new CommandLine(buildCommand).parseArgs(); + buildCommand.execute(); + } + String buildLog = readOutput(true); + Assert.assertEquals(buildLog.replace("\r", "").replace("\\", "/"), + getOutput("build-empty-project-with-build-tools.txt")); } - @Test(description = "Build an empty package with tests only") - public void testBuildEmptyProjectWithTestsOnly() throws IOException { + @Test(description = "Build an empty package with tests only", dataProvider = "optimizeDependencyCompilation") + public void testBuildEmptyProjectWithTestsOnly(Boolean optimizeDependencyCompilation) throws IOException { Path projectPath = this.testResources.resolve("emptyProjectWithTestsOnly"); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, + optimizeDependencyCompilation); new CommandLine(buildCommand).parseArgs(); buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-empty-project-with-tests-only.txt")); } @@ -658,7 +681,7 @@ public void testBuildEmptyProjectWithNonDefaultModules() throws IOException { buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-empty-project-with-nondefault-modules.txt")); } @@ -672,7 +695,7 @@ public void testBuildEmptyProjectWithNonDefaultModulesTestOnly() throws IOExcept buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-empty-project-with-nondefault-modules-tests-only.txt")); } @@ -683,10 +706,13 @@ public void testBuildEmptyNonDefaultModule() throws IOException { BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); new CommandLine(buildCommand).parseArgs(); - buildCommand.execute(); - String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), - getOutput("build-empty-nondefault-module.txt")); + try { + buildCommand.execute(); + } catch (BLauncherException e) { + List messages = e.getMessages(); + Assert.assertEquals(messages.size(), 1); + Assert.assertEquals(messages.get(0), getOutput("build-empty-nondefault-module.txt")); + } } @Test(description = "Build a package with an invalid user name") @@ -723,7 +749,7 @@ public void testConsistentConflictedJarsReporting() throws IOException { new CommandLine(buildCommand).parseArgs(); buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-conflicted-jars-project.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-conflicted-jars-project.txt")); } } @@ -736,8 +762,8 @@ public void testDumpBuildTimeForPackage() throws IOException { buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertTrue(buildLog.replaceAll("\r", "").contains(getOutput("dump-build-time-package.txt"))); - validateBuildTimeInfo(buildLog.replaceAll("\r", "")); + Assert.assertTrue(buildLog.replace("\r", "").contains(getOutput("dump-build-time-package.txt"))); + validateBuildTimeInfo(buildLog.replace("\r", "")); Assert.assertTrue(Files.exists(projectPath.resolve("target").resolve("build-time.json"))); Assert.assertTrue(projectPath.resolve("target").resolve("build-time.json").toFile().length() > 0); @@ -753,8 +779,8 @@ public void testDumpBuildTimeForStandaloneFile() throws IOException { buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertTrue(buildLog.replaceAll("\r", "").contains(getOutput("dump-build-time-standalone.txt"))); - validateBuildTimeInfo(buildLog.replaceAll("\r", "")); + Assert.assertTrue(buildLog.replace("\r", "").contains(getOutput("dump-build-time-standalone.txt"))); + validateBuildTimeInfo(buildLog.replace("\r", "")); Assert.assertTrue(Files.exists(this.testResources.resolve("valid-bal-file").resolve("build-time.json"))); Assert.assertTrue( @@ -803,11 +829,13 @@ public void testBuildEmptyPackage() throws IOException { BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); new CommandLine(buildCommand).parseArgs(); - buildCommand.execute(); - - String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), - getOutput("build-empty-package.txt")); + try { + buildCommand.execute(); + } catch (BLauncherException e) { + List messages = e.getMessages(); + Assert.assertEquals(messages.size(), 1); + Assert.assertEquals(messages.get(0), getOutput("build-empty-package.txt")); + } } @Test(description = "Build an empty package with compiler plugin") @@ -817,15 +845,17 @@ public void testBuildEmptyPackageWithCompilerPlugin() throws IOException { BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); new CommandLine(buildCommand).parseArgs(); - buildCommand.execute(); - - String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), - getOutput("build-empty-package.txt")); + try { + buildCommand.execute(); + } catch (BLauncherException e) { + List messages = e.getMessages(); + Assert.assertEquals(messages.size(), 1); + Assert.assertEquals(messages.get(0), getOutput("build-empty-package.txt")); + } } - @Test(description = "Build a ballerina project with the flag dump-graph") - public void testBuildBalProjectWithDumpGraphFlag() throws IOException { + @Test(dataProvider = "optimizeDependencyCompilation") + public void testBuildBalProjectWithDumpGraphFlag(Boolean optimizeDependencyCompilation) throws IOException { Path dumpGraphResourcePath = this.testResources.resolve("projectsForDumpGraph"); BCompileUtil.compileAndCacheBala(dumpGraphResourcePath.resolve("package_c"), testDistCacheDirectory, projectEnvironmentBuilder); @@ -835,10 +865,11 @@ public void testBuildBalProjectWithDumpGraphFlag() throws IOException { Path projectPath = dumpGraphResourcePath.resolve("package_a"); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, + optimizeDependencyCompilation); new CommandLine(buildCommand).parseArgs("--dump-graph"); buildCommand.execute(); - String buildLog = readOutput(true).replaceAll("\r", "").strip(); + String buildLog = readOutput(true).replace("\r", "").strip(); Assert.assertEquals(buildLog, getOutput("build-project-with-dump-graph.txt")); Assert.assertTrue(projectPath.resolve("target").resolve("cache").resolve("foo") @@ -848,8 +879,8 @@ public void testBuildBalProjectWithDumpGraphFlag() throws IOException { ProjectUtils.deleteDirectory(projectPath.resolve("target")); } - @Test(description = "Build a ballerina project with the flag dump-raw-graphs") - public void testBuildBalProjectWithDumpRawGraphsFlag() throws IOException { + @Test(dataProvider = "optimizeDependencyCompilation") + public void testBuildBalProjectWithDumpRawGraphsFlag(Boolean optimizeDependencyCompilation) throws IOException { Path dumpGraphResourcePath = this.testResources.resolve("projectsForDumpGraph"); BCompileUtil.compileAndCacheBala(dumpGraphResourcePath.resolve("package_c"), testDistCacheDirectory, projectEnvironmentBuilder); @@ -859,10 +890,11 @@ public void testBuildBalProjectWithDumpRawGraphsFlag() throws IOException { Path projectPath = dumpGraphResourcePath.resolve("package_a"); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, + optimizeDependencyCompilation); new CommandLine(buildCommand).parseArgs("--dump-raw-graphs"); buildCommand.execute(); - String buildLog = readOutput(true).replaceAll("\r", "").strip(); + String buildLog = readOutput(true).replace("\r", "").strip(); Assert.assertEquals(buildLog, getOutput("build-project-with-dump-raw-graphs.txt")); Assert.assertTrue(projectPath.resolve("target").resolve("cache").resolve("foo") @@ -872,6 +904,31 @@ public void testBuildBalProjectWithDumpRawGraphsFlag() throws IOException { ProjectUtils.deleteDirectory(projectPath.resolve("target")); } + @Test(description = "Build a package with corrupted Dependencies.toml file") + public void testBuildWithCorruptedDependenciesToml() throws IOException { + Path projectPath = this.testResources.resolve("corrupted-dependecies-toml-file"); + cleanTarget(projectPath); + System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); + Path sourcePath = projectPath.resolve("Dependencies-corrupt.toml"); + Path destinationPath = projectPath.resolve("Dependencies.toml"); + Files.copy(sourcePath, destinationPath); + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); + new CommandLine(buildCommand); + buildCommand.execute(); + String buildLog = readOutput(true); + Assert.assertEquals( + buildLog.replaceAll("\r", ""), + getOutput("corrupted-dependencies-toml.txt").replaceAll("\r", "")); + String depContent = Files.readString(projectPath.resolve("Dependencies.toml"), Charset.defaultCharset()) + .replace("\r" , ""); + String ballerinaShortVersion = RepoUtils.getBallerinaShortVersion(); + String corrcetDepContent = Files.readString(projectPath.resolve("Dependencies-corrected.toml"), + Charset.defaultCharset()).replace("\r" , "") + .replace("DIST_VERSION", ballerinaShortVersion); + Assert.assertEquals(depContent, corrcetDepContent); + Files.delete(destinationPath); + } + @Test(description = "Test bir cached project build performance") public void testBirCachedProjectBuildPerformance() { Path projectPath = this.testResources.resolve("noClassDefProject"); @@ -914,8 +971,9 @@ public void testBirCachedProjectBuildPerformanceAfterTestCommand() { "second code gen duration is greater than the expected value"); } - @Test(description = "Build a valid ballerina project with a custom maven repo") - public void testBuildBalProjectWithCustomMavenRepo() throws IOException { + @Test(description = "Build a valid ballerina project with a custom maven repo", + dataProvider = "optimizeDependencyCompilation") + public void testBuildBalProjectWithCustomMavenRepo(Boolean optimizeDependencyCompilation) throws IOException { String username = System.getenv("publishUser"); String password = System.getenv("publishPAT"); @@ -923,8 +981,9 @@ public void testBuildBalProjectWithCustomMavenRepo() throws IOException { Path projectPath = this.testResources.resolve("validProjectWithCustomMavenRepo"); String content = Files.readString(projectPath.resolve("Ballerina.toml"), Charset.defaultCharset()) .replace("{{username}}", username).replace("{{password}}", password); - Files.write(projectPath.resolve("Ballerina.toml"), content.getBytes(Charset.defaultCharset())); - BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); + Files.writeString(projectPath.resolve("Ballerina.toml"), content, Charset.defaultCharset()); + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, + optimizeDependencyCompilation); new CommandLine(buildCommand).parseArgs(projectPath.toString()); buildCommand.execute(); Assert.assertTrue(projectPath.resolve("target").resolve("platform-libs").resolve("org") @@ -954,16 +1013,18 @@ public void publishDependencies() { testDistCacheDirectory, projectEnvironmentBuilder); } - @Test(description = "Build a new ballerina project without sticky flag", groups = {"proj-with-deps-update-policy"}) - public void testBuildNewBalProjectWithoutStickyFlag() throws IOException { + @Test(description = "Build a new ballerina project without sticky flag", groups = {"proj-with-deps-update-policy"}, + dataProvider = "optimizeDependencyCompilation") + public void testBuildNewBalProjectWithoutStickyFlag(Boolean optimizeDependencyCompilation) throws IOException { Path projectPath = testResources.resolve("dep-dist-version-projects").resolve("newPackage"); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, + optimizeDependencyCompilation); new CommandLine(buildCommand).parseArgs(); buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-new-proj-with-dep.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-new-proj-with-dep.txt")); // Dependencies.toml should have the latest versions of the dependencies Path actualDependenciesToml = projectPath.resolve("Dependencies.toml"); @@ -977,16 +1038,18 @@ public void testBuildNewBalProjectWithoutStickyFlag() throws IOException { deleteDirectory(projectPath.resolve("target")); } - @Test(description = "Build a new ballerina project with sticky flag", groups = {"proj-with-deps-update-policy"}) - public void testBuildNewBalProjectWithStickyFlag() throws IOException { + @Test(description = "Build a new ballerina project with sticky flag", groups = {"proj-with-deps-update-policy"}, + dataProvider = "optimizeDependencyCompilation") + public void testBuildNewBalProjectWithStickyFlag(Boolean optimizeDependencyCompilation) throws IOException { Path projectPath = testResources.resolve("dep-dist-version-projects").resolve("newPackage"); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, + optimizeDependencyCompilation); new CommandLine(buildCommand).parseArgs("--sticky"); buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-new-proj-with-dep.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-new-proj-with-dep.txt")); // Dependencies.toml should have the latest versions of the dependencies Path actualDependenciesToml = projectPath.resolve("Dependencies.toml"); @@ -1001,21 +1064,23 @@ public void testBuildNewBalProjectWithStickyFlag() throws IOException { } @Test(description = "Build a project already built with an older distribution without sticky flag", - groups = {"proj-with-deps-update-policy"}) - public void testBuildProjectPrecompiledWithOlderDistWithoutStickyFlag() throws IOException { + groups = {"proj-with-deps-update-policy"}, dataProvider = "optimizeDependencyCompilation") + public void testBuildProjectPrecompiledWithOlderDistWithoutStickyFlag(Boolean optimizeDependencyCompilation) + throws IOException { Path projectPath = testResources.resolve("dep-dist-version-projects").resolve("preCompiledPackage"); replaceDependenciesTomlContent(projectPath, "**INSERT_DISTRIBUTION_VERSION_HERE**", "2201.5.0"); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, + optimizeDependencyCompilation); new CommandLine(buildCommand).parseArgs(); buildCommand.execute(); String buildLog = readOutput(true); Assert.assertEquals( - buildLog.replaceAll("\r", ""), + buildLog.replace("\r", ""), getOutput("build-old-dist-precomp-proj-without-sticky.txt") - .replaceAll("INSERT_NEW_DIST_VERSION_HERE", getNewVersionForOldDistWarning()) - .replaceAll("INSERT_OLD_DIST_VERSION_HERE", getOldVersionForOldDistWarning("2201.5.0"))); + .replace("INSERT_NEW_DIST_VERSION_HERE", getNewVersionForOldDistWarning()) + .replace("INSERT_OLD_DIST_VERSION_HERE", getOldVersionForOldDistWarning("2201.5.0"))); // Dependencies.toml should be updated to the latest minor versions. // depA:1.0.0 -> depA:1.1.0 @@ -1034,21 +1099,23 @@ public void testBuildProjectPrecompiledWithOlderDistWithoutStickyFlag() throws I } @Test(description = "Build a project already built with an older distribution with sticky flag", - groups = {"proj-with-deps-update-policy"}) - public void testBuildProjectPrecompiledWithOlderDistWithStickyFlag() throws IOException { + groups = {"proj-with-deps-update-policy"}, dataProvider = "optimizeDependencyCompilation") + public void testBuildProjectPrecompiledWithOlderDistWithStickyFlag(Boolean optimizeDependencyCompilation) + throws IOException { Path projectPath = testResources.resolve("dep-dist-version-projects").resolve("preCompiledPackage"); replaceDependenciesTomlContent(projectPath, "**INSERT_DISTRIBUTION_VERSION_HERE**", "2201.5.0"); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, + optimizeDependencyCompilation); new CommandLine(buildCommand).parseArgs("--sticky"); buildCommand.execute(); String buildLog = readOutput(true); Assert.assertEquals( - buildLog.replaceAll("\r", ""), + buildLog.replace("\r", ""), getOutput("build-old-dist-precomp-proj-with-sticky.txt") - .replaceAll("INSERT_NEW_DIST_VERSION_HERE", getNewVersionForOldDistWarning()) - .replaceAll("INSERT_OLD_DIST_VERSION_HERE", getOldVersionForOldDistWarning("2201.5.0"))); + .replace("INSERT_NEW_DIST_VERSION_HERE", getNewVersionForOldDistWarning()) + .replace("INSERT_OLD_DIST_VERSION_HERE", getOldVersionForOldDistWarning("2201.5.0"))); // Dependencies should stick to the ones already in Dependencies.toml. // depA:1.0.0 -> depA:1.0.0 @@ -1066,22 +1133,24 @@ public void testBuildProjectPrecompiledWithOlderDistWithStickyFlag() throws IOEx } @Test(description = "Build a project already built with an U4 or older distribution without sticky flag", - groups = {"proj-with-deps-update-policy"}) - public void testBuildProjectPrecompiledWithNoDistWithoutStickyFlag() throws IOException { + groups = {"proj-with-deps-update-policy"}, dataProvider = "optimizeDependencyCompilation") + public void testBuildProjectPrecompiledWithNoDistWithoutStickyFlag(Boolean optimizeDependencyCompilation) + throws IOException { Path projectPath = testResources.resolve("dep-dist-version-projects").resolve("preCompiledPackage"); replaceDependenciesTomlContent( projectPath, "distribution-version = \"**INSERT_DISTRIBUTION_VERSION_HERE**\"", ""); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, + optimizeDependencyCompilation); new CommandLine(buildCommand).parseArgs(); buildCommand.execute(); String buildLog = readOutput(true); Assert.assertEquals( - buildLog.replaceAll("\r", ""), + buildLog.replace("\r", ""), getOutput("build-old-dist-precomp-proj-without-sticky.txt") - .replaceAll("INSERT_NEW_DIST_VERSION_HERE", getNewVersionForOldDistWarning()) - .replaceAll("INSERT_OLD_DIST_VERSION_HERE", "4 or an older Update")); + .replace("INSERT_NEW_DIST_VERSION_HERE", getNewVersionForOldDistWarning()) + .replace("INSERT_OLD_DIST_VERSION_HERE", "4 or an older Update")); // Dependencies.toml should be updated to the latest minor versions. // depA:1.0.0 -> depA:1.1.0 @@ -1112,10 +1181,10 @@ public void testBuildProjectPrecompiledWithNoDistWithStickyFlag() throws IOExcep buildCommand.execute(); String buildLog = readOutput(true); Assert.assertEquals( - buildLog.replaceAll("\r", ""), + buildLog.replace("\r", ""), getOutput("build-old-dist-precomp-proj-with-sticky.txt") - .replaceAll("INSERT_NEW_DIST_VERSION_HERE", getNewVersionForOldDistWarning()) - .replaceAll("INSERT_OLD_DIST_VERSION_HERE", "4 or an older Update")); + .replace("INSERT_NEW_DIST_VERSION_HERE", getNewVersionForOldDistWarning()) + .replace("INSERT_OLD_DIST_VERSION_HERE", "4 or an older Update")); // Dependencies should stick to the ones already in Dependencies.toml. // depA:1.0.0 -> depA:1.0.0 @@ -1144,7 +1213,7 @@ public void testBuildProjectPrecompiledWithCurrentDistWithoutStickyFlag() throws new CommandLine(buildCommand).parseArgs(); buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-curr-dist-precomp-proj-with-dep.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-curr-dist-precomp-proj-with-dep.txt")); // Dependencies.toml should be updated to the latest patch versions. // depA:1.0.0 -> depA:1.0.1 @@ -1174,7 +1243,7 @@ public void testBuildProjectPrecompiledWithCurrentDistWithStickyFlag() throws IO new CommandLine(buildCommand).parseArgs("--sticky"); buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-curr-dist-precomp-proj-with-dep.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-curr-dist-precomp-proj-with-dep.txt")); // Dependencies should stick to the ones already in Dependencies.toml. // depA:1.0.0 -> depA:1.0.0 @@ -1229,7 +1298,7 @@ public void testBuildProjectWithBuildToolTomlPropertyDiagnostics(String projectN buildCommand.execute(); } catch (BLauncherException e) { String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput(outputFile)); Assert.assertEquals(error, e.getDetailedMessages().get(0)); } @@ -1243,7 +1312,7 @@ public void testBuildProjectWithBuildTool() throws IOException { new CommandLine(buildCommand).parseArgs(); buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", "").replace("\\", "/"), getOutput("build-bal-project-with-build-tool.txt")); } @@ -1257,12 +1326,28 @@ public void testBuildProjectWithBuildToolNotFound() throws IOException { buildCommand.execute(); } catch (BLauncherException e) { String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-bal-project-with-build-tool-not-found.txt")); Assert.assertEquals("error: build tool execution contains errors", e.getDetailedMessages().get(0)); } } + @Test(description = "Build a project with invalid fields in TOML array 'dependency'") + public void testBuildProjectWithInvalidDependencyArrayInBallerinaToml() throws IOException { + Path projectPath = this.testResources.resolve("invalid-dependency-array-project"); + System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); + new CommandLine(buildCommand).parseArgs(); + try { + buildCommand.execute(); + } catch (BLauncherException e) { + Assert.assertEquals("error: compilation contains errors", e.getDetailedMessages().get(0)); + String buildLog = readOutput(true); + Assert.assertEquals(buildLog.replace("\r", ""), + getOutput("build-bal-project-with-invalid-dependency-array.txt")); + } + } + private String getNewVersionForOldDistWarning() { SemanticVersion currentDistributionVersion = SemanticVersion.from(RepoUtils.getBallerinaShortVersion()); String currentVersionForDiagnostic = String.valueOf(currentDistributionVersion.minor()); @@ -1275,21 +1360,17 @@ private String getNewVersionForOldDistWarning() { private String getOldVersionForOldDistWarning(String version) { SemanticVersion prevDistributionVersion = SemanticVersion.from(version); String prevVersionForDiagnostic; - if (null != prevDistributionVersion) { - prevVersionForDiagnostic = String.valueOf(prevDistributionVersion.minor()); - if (prevDistributionVersion.patch() != 0) { - prevVersionForDiagnostic += DOT + prevDistributionVersion.patch(); - } - } else { - prevVersionForDiagnostic = "4 or an older Update"; + prevVersionForDiagnostic = String.valueOf(prevDistributionVersion.minor()); + if (prevDistributionVersion.patch() != 0) { + prevVersionForDiagnostic += DOT + prevDistributionVersion.patch(); } return prevVersionForDiagnostic; } static class Copy extends SimpleFileVisitor { - private Path fromPath; - private Path toPath; - private StandardCopyOption copyOption; + private final Path fromPath; + private final Path toPath; + private final StandardCopyOption copyOption; public Copy(Path fromPath, Path toPath, StandardCopyOption copyOption) { diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BuildNativeImageCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BuildNativeImageCommandTest.java index 3bc5f382dc34..be6b31a963a6 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BuildNativeImageCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/BuildNativeImageCommandTest.java @@ -32,7 +32,6 @@ import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Objects; import static io.ballerina.projects.util.ProjectConstants.DIST_CACHE_DIRECTORY; @@ -48,19 +47,20 @@ public class BuildNativeImageCommandTest extends BaseCommandTest { private Path testDistCacheDirectory; ProjectEnvironmentBuilder projectEnvironmentBuilder; + @Override @BeforeClass public void setup() throws IOException { super.setup(); try { this.testResources = super.tmpDir.resolve("native-image-resources"); - Path testBuildDirectory = Paths.get("build").toAbsolutePath(); + Path testBuildDirectory = Path.of("build").toAbsolutePath(); this.testDistCacheDirectory = testBuildDirectory.resolve(DIST_CACHE_DIRECTORY); - Path customUserHome = Paths.get("build", "user-home"); + Path customUserHome = Path.of("build", "user-home"); Environment environment = EnvironmentBuilder.getBuilder().setUserHome(customUserHome).build(); projectEnvironmentBuilder = ProjectEnvironmentBuilder.getBuilder(environment); URI testResourcesURI = Objects.requireNonNull( getClass().getClassLoader().getResource("test-resources")).toURI(); - Files.walkFileTree(Paths.get(testResourcesURI), new TestCommandTest.Copy(Paths.get(testResourcesURI), + Files.walkFileTree(Path.of(testResourcesURI), new TestCommandTest.Copy(Path.of(testResourcesURI), this.testResources)); } catch (URISyntaxException e) { Assert.fail("error loading resources"); @@ -74,7 +74,7 @@ public void testBuildProjectWithNativeImage() { BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, false, true, ""); // non existing bal file - new CommandLine(buildCommand).parse(); + new CommandLine(buildCommand).parseArgs(); buildCommand.execute(); Assert.assertTrue(projectPath.resolve("target").resolve("bin").resolve("winery").toFile().exists()); @@ -88,7 +88,7 @@ public void testBuildProjectWithAdditionalArgs() throws IOException { BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, false, true, "-H:Name=hoo"); // non existing bal file - new CommandLine(buildCommand).parse(); + new CommandLine(buildCommand).parseArgs(); buildCommand.execute(); String buildLog = readOutput(true); Assert.assertTrue(buildLog.contains("Generating 'hoo' (executable)")); @@ -108,7 +108,7 @@ public void testBuildBalFileWithNativeImage() { // set valid source root BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, false, true, ""); // name of the file as argument - new CommandLine(buildCommand).parse(projectPath.toString()); + new CommandLine(buildCommand).parseArgs(projectPath.toString()); buildCommand.execute(); Assert.assertTrue(projectPath.resolve("target").resolve("native").resolve("winery").toFile().exists()); @@ -125,7 +125,7 @@ public void testBuildBalFileWithAdditionalArgs() throws IOException { System.setProperty(ProjectConstants.USER_DIR, this.testResources.resolve("valid-test-bal-file").toString()); BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false, false, true, "-H:Name=hoo"); - new CommandLine(buildCommand).parse(projectPath.toString()); + new CommandLine(buildCommand).parseArgs(projectPath.toString()); buildCommand.execute(); String buildLog = readOutput(true); Assert.assertTrue(buildLog.contains("Generating 'hoo' (executable)")); diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/CleanCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/CleanCommandTest.java index ecaa69870fcb..9ee1f1a9f2d9 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/CleanCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/CleanCommandTest.java @@ -29,7 +29,6 @@ import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Objects; import static io.ballerina.cli.cmd.CommandOutputUtils.getOutput; @@ -42,6 +41,7 @@ public class CleanCommandTest extends BaseCommandTest { private Path testResources; + @Override @BeforeClass public void setup() throws IOException { super.setup(); @@ -49,7 +49,7 @@ public void setup() throws IOException { this.testResources = super.tmpDir.resolve("build-test-resources"); URI testResourcesURI = Objects.requireNonNull( getClass().getClassLoader().getResource("test-resources")).toURI(); - Files.walkFileTree(Paths.get(testResourcesURI), new BuildCommandTest.Copy(Paths.get(testResourcesURI), + Files.walkFileTree(Path.of(testResourcesURI), new BuildCommandTest.Copy(Path.of(testResourcesURI), this.testResources)); } catch (URISyntaxException e) { Assert.fail("error loading resources"); @@ -103,30 +103,29 @@ public void testCleanCommandInProjectWithCustomTarget() throws IOException { @Test(description = "Test clean command on a ballerina project with custom target dir.") public void testCleanCommandNonExistentTargetAndGenerated() throws IOException { Path projectPath = this.testResources.resolve("validProjectWithTargetAndGenerated"); - Path customTargetDir = Paths.get("customTargetDirNotExists"); + Path customTargetDir = Path.of("customTargetDirNotExists"); Path generatedDir = projectPath.resolve(ProjectConstants.GENERATED_MODULES_ROOT); Assert.assertTrue(Files.notExists(customTargetDir)); CleanCommand cleanCommand = new CleanCommand(projectPath, printStream, false, customTargetDir); cleanCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("clean-non-existent-target.txt") - .replaceAll("%TARGET_LOCATION%", customTargetDir.toString())); + .replace("%TARGET_LOCATION%", customTargetDir.toString())); } @Test(description = "Test clean command on a regular file as the custom target dir.") public void testCleanCommandOnRegularFile() throws IOException { Path projectPath = this.testResources.resolve("validProjectWithTargetAndGenerated"); - Path generatedDir = projectPath.resolve(ProjectConstants.GENERATED_MODULES_ROOT); Path customTargetDir = projectPath.resolve("main.bal"); Assert.assertTrue(Files.exists(customTargetDir)); CleanCommand cleanCommand = new CleanCommand(projectPath, printStream, false, customTargetDir); cleanCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("clean-regular-file.txt") - .replaceAll("%TARGET_LOCATION%", customTargetDir.toString())); + .replace("%TARGET_LOCATION%", customTargetDir.toString())); } } diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/CommandOutputUtils.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/CommandOutputUtils.java index 5f2fcd202ff6..c391bc2fecea 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/CommandOutputUtils.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/CommandOutputUtils.java @@ -29,7 +29,6 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import static io.ballerina.cli.utils.OsUtils.isWindows; @@ -38,17 +37,16 @@ * * @since 2.0.0 */ -public class CommandOutputUtils { +public final class CommandOutputUtils { - private static final Path commandOutputsDir = Paths - .get("src", "test", "resources", "test-resources", "command-outputs"); + private static final Path commandOutputsDir = Path.of("src/test/resources/test-resources/command-outputs"); private CommandOutputUtils() { } static String readFileAsString(Path filePath) throws IOException { if (isWindows()) { - return Files.readString(filePath).replaceAll("\r", ""); + return Files.readString(filePath).replace("\r", ""); } else { return Files.readString(filePath); } @@ -57,7 +55,7 @@ static String readFileAsString(Path filePath) throws IOException { static String getOutput(String outputFileName) throws IOException { if (isWindows()) { return Files.readString(commandOutputsDir.resolve("windows").resolve(outputFileName)) - .replaceAll("\r", ""); + .replace("\r", ""); } else { return Files.readString(commandOutputsDir.resolve("unix").resolve(outputFileName)); } diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/CommandUtilTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/CommandUtilTest.java index 08b193c629a1..f4be8be0fa56 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/CommandUtilTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/CommandUtilTest.java @@ -33,7 +33,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import static io.ballerina.cli.cmd.CommandOutputUtils.readFileAsString; import static io.ballerina.cli.cmd.CommandUtil.writeBallerinaToml; @@ -48,8 +47,7 @@ */ public class CommandUtilTest { - private static final Path COMMAND_UTIL_RESOURCE_DIR = Paths - .get("src", "test", "resources", "test-resources", "command-util"); + private static final Path COMMAND_UTIL_RESOURCE_DIR = Path.of("src/test/resources/test-resources/command-util"); @Test(description = "Test write new project Ballerina.toml from template package.json") public void testWriteBallerinaToml() throws IOException { @@ -103,6 +101,6 @@ public void testWriteDependenciesToml() throws IOException { @AfterMethod public void tearDown() throws IOException { Files.deleteIfExists(COMMAND_UTIL_RESOURCE_DIR.resolve(BALLERINA_TOML)); - Files.deleteIfExists(COMMAND_UTIL_RESOURCE_DIR.resolve(DEPENDENCIES_TOML)); + Files.deleteIfExists(COMMAND_UTIL_RESOURCE_DIR.resolve("hello_template_project").resolve(DEPENDENCIES_TOML)); } } diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/DeprecateCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/DeprecateCommandTest.java index c56553b8fae1..1e0cd82d78cd 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/DeprecateCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/DeprecateCommandTest.java @@ -38,7 +38,7 @@ public void testDeprecationWithInvalidOrg() throws IOException { deprecationCommand.execute(); String buildLog = readOutput(true); - String actual = buildLog.replaceAll("\r", ""); + String actual = buildLog.replace("\r", ""); Assert.assertTrue(actual.contains("ballerina: invalid organization name. Organization name can only contain " + "alphanumeric values with lower case letters and cannot start with numeric values, " + "org_name = my-newdil")); @@ -51,7 +51,7 @@ public void testDeprecationWithInvalidPackageName() throws IOException { deprecationCommand.execute(); String buildLog = readOutput(true); - String actual = buildLog.replaceAll("\r", ""); + String actual = buildLog.replace("\r", ""); Assert.assertTrue(actual.contains("ballerina: invalid package name provided")); } @@ -62,8 +62,11 @@ public void testDeprecationWithInvalidVersion() throws IOException { deprecationCommand.execute(); String buildLog = readOutput(true); - String actual = buildLog.replaceAll("\r", ""); - Assert.assertTrue(actual.contains("ballerina: invalid request received. error occurred finding package")); + String actual = buildLog.replace("\r", ""); + Assert.assertTrue(actual.contains( + "ballerina: error: could not connect to remote repository to find package: mynewdil/deppack:xxx. " + + "reason: package not found: mynewdil/deppack:xxx_java17"), + actual); } @Test(description = "Test deprecate with invalid message") @@ -74,7 +77,7 @@ public void testDeprecationWithInvalidMessage() throws IOException { deprecationCommand.execute(); String buildLog = readOutput(true); - String actual = buildLog.replaceAll("\r", ""); + String actual = buildLog.replace("\r", ""); Assert.assertTrue(actual.contains("ballerina: invalid deprecation message. " + "The message cannot contain non-space whitespace or back slash characters.")); Assert.assertTrue(actual.contains("bal deprecate {/:} [OPTIONS]")); @@ -87,7 +90,7 @@ public void testDeprecationWithUnusedFlags() throws IOException { deprecationCommand.execute(); String buildLog = readOutput(true); - String actual = buildLog.replaceAll("\r", ""); + String actual = buildLog.replace("\r", ""); Assert.assertTrue(actual.contains("warning: ignoring --message flag since this is an undo request")); } @@ -98,7 +101,7 @@ public void testDeprecationWithTooManyArgs() throws IOException { deprecationCommand.execute(); String buildLog = readOutput(true); - String actual = buildLog.replaceAll("\r", ""); + String actual = buildLog.replace("\r", ""); Assert.assertTrue(actual.contains("ballerina: too many arguments")); Assert.assertTrue(actual.contains("bal deprecate ")); } diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/DocCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/DocCommandTest.java index 0c9f249c2d57..a24000b1605d 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/DocCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/DocCommandTest.java @@ -27,7 +27,6 @@ import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Objects; import static io.ballerina.cli.cmd.CommandOutputUtils.getOutput; @@ -40,6 +39,7 @@ public class DocCommandTest extends BaseCommandTest { private Path testResources; + @Override @BeforeClass public void setup() throws IOException { super.setup(); @@ -47,7 +47,7 @@ public void setup() throws IOException { this.testResources = super.tmpDir.resolve("build-test-resources"); URI testResourcesURI = Objects.requireNonNull( getClass().getClassLoader().getResource("test-resources")).toURI(); - Files.walkFileTree(Paths.get(testResourcesURI), new BuildCommandTest.Copy(Paths.get(testResourcesURI), + Files.walkFileTree(Path.of(testResourcesURI), new BuildCommandTest.Copy(Path.of(testResourcesURI), this.testResources)); } catch (URISyntaxException e) { Assert.fail("error loading resources"); @@ -55,17 +55,23 @@ public void setup() throws IOException { } @Test(description = "Test doc command on a ballerina project.") - public void testDocCommand() throws IOException { + public void testDocCommand() { Path projectPath = this.testResources.resolve("doc_project"); System.setProperty("user.dir", projectPath.toString()); + Path destinationPath = projectPath.resolve("target") + .resolve("apidocs").resolve("foo").resolve("winery").resolve("0.1.0"); DocCommand docCommand = new DocCommand(this.printStream, this.printStream, false); docCommand.execute(); - Assert.assertTrue(Files.exists(this.testResources.resolve("doc_project").resolve("target") - .resolve("apidocs").resolve("foo").resolve("winery").resolve("0.1.0").resolve("index.html"))); + Assert.assertTrue(Files.exists(destinationPath.resolve("api-docs.js"))); + Assert.assertTrue(Files.exists(destinationPath.resolve("api-docs.json"))); - Files.delete(this.testResources.resolve("doc_project").resolve("target") - .resolve("apidocs").resolve("foo").resolve("winery").resolve("0.1.0").resolve("index.html")); + /* Verify if all the UI components are present. */ + Assert.assertTrue(Files.exists(destinationPath.resolve("bundle.js"))); + Assert.assertTrue(Files.exists(destinationPath.resolve("favicon.ico"))); + Assert.assertTrue(Files.exists(destinationPath.resolve("globals.css"))); + Assert.assertTrue(Files.exists(destinationPath.resolve("index.html"))); + Assert.assertTrue(Files.exists(destinationPath.resolve("vercel.svg"))); } @Test(description = "Test doc command on a ballerina project with custom target dir.") @@ -92,7 +98,7 @@ public void testDocCommandWithBuildTool() throws IOException { docCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("doc-with-build-tool.txt")); Assert.assertTrue(Files.exists(this.testResources.resolve("doc_project_with_build_tool").resolve("target") diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/GraphCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/GraphCommandTest.java index 05ba384604ab..1d84e44e4bc3 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/GraphCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/GraphCommandTest.java @@ -18,8 +18,15 @@ package io.ballerina.cli.cmd; +import io.ballerina.cli.launcher.BLauncherException; +import io.ballerina.projects.ProjectEnvironmentBuilder; +import io.ballerina.projects.environment.Environment; +import io.ballerina.projects.environment.EnvironmentBuilder; +import io.ballerina.projects.util.BuildToolUtils; import org.ballerinalang.compiler.BLangCompilerException; import org.ballerinalang.test.BCompileUtil; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -37,9 +44,14 @@ import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; +import java.util.List; import java.util.Objects; +import static io.ballerina.cli.cmd.CommandOutputUtils.getOutput; +import static io.ballerina.cli.cmd.CommandOutputUtils.replaceDependenciesTomlContent; +import static io.ballerina.projects.util.ProjectConstants.DIST_CACHE_DIRECTORY; +import static io.ballerina.projects.util.ProjectConstants.USER_DIR_PROPERTY; + /** * Graph command tests. * @@ -47,10 +59,18 @@ */ public class GraphCommandTest extends BaseCommandTest { private Path testResources; + private Path testDistCacheDirectory; + private ProjectEnvironmentBuilder projectEnvironmentBuilder; + @Override @BeforeClass public void setup() throws IOException { super.setup(); + Path testBuildDirectory = Path.of("build").toAbsolutePath(); + testDistCacheDirectory = testBuildDirectory.resolve(DIST_CACHE_DIRECTORY); + Path customUserHome = Path.of("build", "user-home"); + Environment environment = EnvironmentBuilder.getBuilder().setUserHome(customUserHome).build(); + projectEnvironmentBuilder = ProjectEnvironmentBuilder.getBuilder(environment); this.testResources = super.tmpDir.resolve("build-test-resources"); Path projectsWithDependencyConflicts = this.testResources.resolve("projectsWithDependencyConflicts") .resolve("package_p"); @@ -203,10 +223,32 @@ public void testEmptyBalProjectGraph() throws IOException { GraphCommand graphCommand = new GraphCommand(emptyPackagePath, printStream, printStream, false); new CommandLine(graphCommand).parseArgs(emptyPackagePath.toString()); - graphCommand.execute(); + try { + graphCommand.execute(); + } catch (BLauncherException e) { + List messages = e.getMessages(); + Assert.assertEquals(messages.size(), 1); + Assert.assertEquals(messages.get(0), getOutput("build-empty-package.txt")); + } + } + @Test(description = "Call bal graph for an empty project with build tools") + public void testEmptyBalProjectGraphWithBuildTools() throws IOException { + BCompileUtil.compileAndCacheBala(testResources.resolve("buildToolResources").resolve("tools") + .resolve("ballerina-generate-file").toString(), testDistCacheDirectory, projectEnvironmentBuilder); + Path emptyPackagePath = this.testResources.resolve("emptyProjectWithBuildTool"); + replaceDependenciesTomlContent(emptyPackagePath, "**INSERT_DISTRIBUTION_VERSION_HERE**", + RepoUtils.getBallerinaShortVersion()); + System.setProperty(USER_DIR_PROPERTY, emptyPackagePath.toString()); + try (MockedStatic repoUtils = Mockito.mockStatic( + BuildToolUtils.class, Mockito.CALLS_REAL_METHODS)) { + repoUtils.when(BuildToolUtils::getCentralBalaDirPath).thenReturn(testDistCacheDirectory.resolve("bala")); + GraphCommand graphCommand = new GraphCommand(emptyPackagePath, printStream, printStream, false); + new CommandLine(graphCommand).parseArgs(emptyPackagePath.toString()); + graphCommand.execute(); + } String actualLog = readFormattedOutput(); - String expectedLog = "ballerina: package is empty. Please add at least one .bal file."; + String expectedLog = CommandOutputUtils.getOutput("graph-empty-project-with-build-tools.txt"); Assert.assertEquals(actualLog, expectedLog); } @@ -352,25 +394,31 @@ public void testBalGraphWithMissingTransitiveDependency() throws IOException { private void copyTestResourcesToTmpDir() throws URISyntaxException, IOException { URI testResourcesURI = Objects.requireNonNull(getClass().getClassLoader().getResource("test-resources")) .toURI(); - Path originalTestResources = Paths.get(testResourcesURI); + Path originalTestResources = Path.of(testResourcesURI); Files.walkFileTree(originalTestResources, new BuildCommandTest.Copy(originalTestResources, this.testResources)); } private void compileAndCacheTestDependencies() { Path dumpGraphResourcePath = this.testResources.resolve("projectsForDumpGraph"); - BCompileUtil.compileAndCacheBala(dumpGraphResourcePath.resolve("package_c").toString()); - BCompileUtil.compileAndCacheBala(dumpGraphResourcePath.resolve("package_b").toString()); + BCompileUtil.compileAndCacheBala(dumpGraphResourcePath.resolve("package_c").toString(), + testDistCacheDirectory, projectEnvironmentBuilder); + BCompileUtil.compileAndCacheBala(dumpGraphResourcePath.resolve("package_b").toString(), + testDistCacheDirectory, projectEnvironmentBuilder); Path dependencyConflictPath = this.testResources.resolve("projectsWithDependencyConflicts"); - BCompileUtil.compileAndCacheBala(dependencyConflictPath.resolve("package_o_1_0_0").toString()); - BCompileUtil.compileAndCacheBala(dependencyConflictPath.resolve("package_o_1_0_2").toString()); - BCompileUtil.compileAndCacheBala(dependencyConflictPath.resolve("package_o_1_1_0").toString()); - BCompileUtil.compileAndCacheBala(dependencyConflictPath.resolve("package_o_2_1_0").toString()); + BCompileUtil.compileAndCacheBala(dependencyConflictPath.resolve("package_o_1_0_0").toString(), + testDistCacheDirectory, projectEnvironmentBuilder); + BCompileUtil.compileAndCacheBala(dependencyConflictPath.resolve("package_o_1_0_2").toString(), + testDistCacheDirectory, projectEnvironmentBuilder); + BCompileUtil.compileAndCacheBala(dependencyConflictPath.resolve("package_o_1_1_0").toString(), + testDistCacheDirectory, projectEnvironmentBuilder); + BCompileUtil.compileAndCacheBala(dependencyConflictPath.resolve("package_o_2_1_0").toString(), + testDistCacheDirectory, projectEnvironmentBuilder); } private String readFormattedOutput() throws IOException { - return readOutput(true).replaceAll("\n\t\n", "\n\n").replaceAll("\r", "").strip(); + return readOutput(true).replace("\n\t\n", "\n\n").replace("\r", "").strip(); } private void replaceDependenciesTomlVersion(Path projectPath) throws IOException { diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/InitCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/InitCommandTest.java index 94ab7e80a367..a5c6ecdb7685 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/InitCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/InitCommandTest.java @@ -49,7 +49,7 @@ public void testInitCommand() throws IOException { System.setProperty(USER_NAME, "testuserorg"); String[] args = {}; InitCommand initCommand = new InitCommand(projectPath, printStream, false); - new CommandLine(initCommand).parse(args); + new CommandLine(initCommand).parseArgs(args); initCommand.execute(); Assert.assertTrue(Files.exists(projectPath)); @@ -87,7 +87,7 @@ public void testInitCommandWithinInvalidCharsDir() throws IOException { System.setProperty(USER_NAME, "testuserorg"); String[] args = {}; InitCommand initCommand = new InitCommand(projectPath, printStream, false); - new CommandLine(initCommand).parse(args); + new CommandLine(initCommand).parseArgs(args); initCommand.execute(); Assert.assertTrue(Files.exists(projectPath)); @@ -245,7 +245,7 @@ public void testInitCommandMultipleArgs() throws IOException { // Test if no arguments was passed in String[] args = {"sample2", "sample3"}; InitCommand initCommand = new InitCommand(tmpDir, printStream, false); - new CommandLine(initCommand).parse(args); + new CommandLine(initCommand).parseArgs(args); initCommand.execute(); Assert.assertTrue(readOutput().contains("too many arguments")); @@ -256,7 +256,7 @@ public void testInitCommandArgAndHelp() throws IOException { // Test if no arguments was passed in String[] args = {"sample2", "--help"}; InitCommand initCommand = new InitCommand(tmpDir, printStream, false); - new CommandLine(initCommand).parse(args); + new CommandLine(initCommand).parseArgs(args); initCommand.execute(); Assert.assertTrue(readOutput().contains( @@ -269,7 +269,7 @@ public void testInitCommandWithHelp() throws IOException { // Test if no arguments was passed in String[] args = {"-h"}; InitCommand initCommand = new InitCommand(tmpDir, printStream, false); - new CommandLine(initCommand).parse(args); + new CommandLine(initCommand).parseArgs(args); initCommand.execute(); Assert.assertTrue(readOutput().contains( @@ -288,10 +288,12 @@ public void testInitCommandInsideDirectoryWithInvalidPackageName() throws IOExce Assert.assertTrue(Files.exists(projectPath)); Assert.assertTrue(Files.exists(projectPath.resolve(ProjectConstants.BALLERINA_TOML))); - String initLog = readOutput().replaceAll("\r", ""); - Assert.assertTrue(initLog.contains("package name is derived as 'my_app'. " + - "Edit the Ballerina.toml to change it.\n\n" + - "Created new package 'my_app'.\n")); + String initLog = readOutput().replace("\r", ""); + Assert.assertTrue(initLog.contains(""" + package name is derived as 'my_app'. Edit the Ballerina.toml to change it. + + Created new package 'my_app'. + """)); } @Test(description = "Test init command with invalid project name") @@ -387,7 +389,7 @@ public void testInitCommandInsideProject() throws IOException { Path projectPath = tmpDir.resolve("sample1"); String[] args = {}; InitCommand initCommand = new InitCommand(projectPath, printStream, false); - new CommandLine(initCommand).parse(args); + new CommandLine(initCommand).parseArgs(args); initCommand.execute(); //initialize a project again @@ -404,7 +406,7 @@ public void testInitCommandWithinBallerinaProject() throws IOException { Files.createDirectory(projectDir); //initialize a project again InitCommand initCommand = new InitCommand(projectDir, printStream, false); - new CommandLine(initCommand).parse(args); + new CommandLine(initCommand).parseArgs(args); initCommand.execute(); Assert.assertTrue(readOutput().contains("directory is already within a Ballerina project")); } diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/NewCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/NewCommandTest.java index 0bd8ae9742e4..a25725186fb5 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/NewCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/NewCommandTest.java @@ -23,6 +23,7 @@ import io.ballerina.projects.util.ProjectConstants; import io.ballerina.projects.util.ProjectUtils; import org.testng.Assert; +import org.testng.SkipException; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; @@ -37,7 +38,6 @@ import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; @@ -45,6 +45,7 @@ import static io.ballerina.cli.cmd.CommandOutputUtils.getOutput; import static io.ballerina.cli.cmd.CommandOutputUtils.readFileAsString; +import static io.ballerina.cli.utils.OsUtils.isWindows; import static io.ballerina.projects.util.ProjectConstants.TOOL_DIR; import static io.ballerina.projects.util.ProjectConstants.USER_NAME; @@ -57,7 +58,7 @@ public class NewCommandTest extends BaseCommandTest { Path testResources; Path centralCache; - private PrintStream errStream = System.err; + private final PrintStream errStream = System.err; @DataProvider(name = "invalidProjectNames") public Object[][] provideInvalidProjectNames() { @@ -67,10 +68,11 @@ public Object[][] provideInvalidProjectNames() { }; } + @Override @BeforeClass public void setup() throws IOException { super.setup(); - testResources = Paths.get("src/test/resources/test-resources"); + testResources = Path.of("src/test/resources/test-resources"); centralCache = homeCache.resolve("repositories/central.ballerina.io").resolve("bala"); Files.createDirectories(centralCache); @@ -109,7 +111,7 @@ public void testNewCommandWithAbsolutePaths(String packagePath) throws IOExcepti Assert.assertTrue(Files.exists(packageDir)); Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.BALLERINA_TOML))); - String name = Paths.get(args[0]).getFileName().toString(); + String name = Path.of(args[0]).getFileName().toString(); String tomlContent = Files.readString( packageDir.resolve(ProjectConstants.BALLERINA_TOML), StandardCharsets.UTF_8); String expectedContent = "[package]\n" + @@ -126,17 +128,19 @@ public void testNewCommandWithAbsolutePaths(String packagePath) throws IOExcepti Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.GITIGNORE_FILE_NAME))); String gitignoreContent = Files.readString( packageDir.resolve(ProjectConstants.GITIGNORE_FILE_NAME), StandardCharsets.UTF_8); - String expectedGitignoreContent = "# Ballerina generates this directory during the compilation of a package. " + - "\n# It contains compiler-generated artifacts and the final executable if this is an application " + - "package.\ntarget/\n" + - "\n" + - "# Ballerina maintains the compiler-generated source code here.\n" + - "# Remove this if you want to commit generated sources.\n" + - "generated/\n" + - "\n" + - "# Contains configuration values used during development time.\n" + - "# See https://ballerina.io/learn/provide-values-to-configurable-variables/ for more details.\n" + - "Config.toml\n"; + String expectedGitignoreContent = """ + # Ballerina generates this directory during the compilation of a package. + # It contains compiler-generated artifacts and the final executable if this is an application package. + target/ + + # Ballerina maintains the compiler-generated source code here. + # Remove this if you want to commit generated sources. + generated/ + + # Contains configuration values used during development time. + # See https://ballerina.io/learn/provide-values-to-configurable-variables/ for more details. + Config.toml + """; Assert.assertEquals(gitignoreContent.trim(), expectedGitignoreContent.trim()); Assert.assertTrue(readOutput().contains("Created new package")); @@ -161,7 +165,7 @@ public void testNewCommandInExistingDirectory() throws IOException { Assert.assertTrue(Files.exists(packageDir)); Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.BALLERINA_TOML))); - String name = Paths.get(args[0]).getFileName().toString(); + String name = Path.of(args[0]).getFileName().toString(); String tomlContent = Files.readString( packageDir.resolve(ProjectConstants.BALLERINA_TOML), StandardCharsets.UTF_8); String expectedContent = "[package]\n" + @@ -178,17 +182,19 @@ public void testNewCommandInExistingDirectory() throws IOException { Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.GITIGNORE_FILE_NAME))); String gitignoreContent = Files.readString( packageDir.resolve(ProjectConstants.GITIGNORE_FILE_NAME), StandardCharsets.UTF_8); - String expectedGitignoreContent = "# Ballerina generates this directory during the compilation of a package. " + - "\n# It contains compiler-generated artifacts and the final executable if this is an application " + - "package.\ntarget/\n" + - "\n" + - "# Ballerina maintains the compiler-generated source code here.\n" + - "# Remove this if you want to commit generated sources.\n" + - "generated/\n" + - "\n" + - "# Contains configuration values used during development time.\n" + - "# See https://ballerina.io/learn/provide-values-to-configurable-variables/ for more details.\n" + - "Config.toml\n"; + String expectedGitignoreContent = """ + # Ballerina generates this directory during the compilation of a package. + # It contains compiler-generated artifacts and the final executable if this is an application package. + target/ + + # Ballerina maintains the compiler-generated source code here. + # Remove this if you want to commit generated sources. + generated/ + + # Contains configuration values used during development time. + # See https://ballerina.io/learn/provide-values-to-configurable-variables/ for more details. + Config.toml + """; Assert.assertEquals(gitignoreContent.trim(), expectedGitignoreContent.trim()); Assert.assertTrue(readOutput().contains("Created new package")); @@ -217,7 +223,7 @@ public void testNewCommandInExistingDirectoryWithExistingBalFilesForDefaultTempl Assert.assertTrue(Files.exists(packageDir)); Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.BALLERINA_TOML))); - String name = Paths.get(args[0]).getFileName().toString(); + String name = Path.of(args[0]).getFileName().toString(); String tomlContent = Files.readString( packageDir.resolve(ProjectConstants.BALLERINA_TOML), StandardCharsets.UTF_8); String expectedContent = "[package]\n" + @@ -234,17 +240,19 @@ public void testNewCommandInExistingDirectoryWithExistingBalFilesForDefaultTempl Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.GITIGNORE_FILE_NAME))); String gitignoreContent = Files.readString( packageDir.resolve(ProjectConstants.GITIGNORE_FILE_NAME), StandardCharsets.UTF_8); - String expectedGitignoreContent = "# Ballerina generates this directory during the compilation of a package. " + - "\n# It contains compiler-generated artifacts and the final executable if this is an application " + - "package.\ntarget/\n" + - "\n" + - "# Ballerina maintains the compiler-generated source code here.\n" + - "# Remove this if you want to commit generated sources.\n" + - "generated/\n" + - "\n" + - "# Contains configuration values used during development time.\n" + - "# See https://ballerina.io/learn/provide-values-to-configurable-variables/ for more details.\n" + - "Config.toml\n"; + String expectedGitignoreContent = """ + # Ballerina generates this directory during the compilation of a package. + # It contains compiler-generated artifacts and the final executable if this is an application package. + target/ + + # Ballerina maintains the compiler-generated source code here. + # Remove this if you want to commit generated sources. + generated/ + + # Contains configuration values used during development time. + # See https://ballerina.io/learn/provide-values-to-configurable-variables/ for more details. + Config.toml + """; Assert.assertEquals(gitignoreContent.trim(), expectedGitignoreContent.trim()); Assert.assertTrue(readOutput().contains("Created new package")); @@ -311,7 +319,7 @@ public void testNewCommandWithExistingPackageFilesDefaultTemplate() throws IOExc Assert.assertTrue(Files.exists(tempPackageDir)); Assert.assertTrue(Files.exists(tempPackageDir.resolve(ProjectConstants.BALLERINA_TOML))); - String name = Paths.get(args[0]).getFileName().toString(); + String name = Path.of(args[0]).getFileName().toString(); String tomlContent = Files.readString( tempPackageDir.resolve(ProjectConstants.BALLERINA_TOML), StandardCharsets.UTF_8); String expectedContent = "[package]\n" + @@ -374,17 +382,19 @@ public void testNewCommandInExistingDirectoryWithInvalidName() throws IOExceptio Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.GITIGNORE_FILE_NAME))); String gitignoreContent = Files.readString( packageDir.resolve(ProjectConstants.GITIGNORE_FILE_NAME), StandardCharsets.UTF_8); - String expectedGitignoreContent = "# Ballerina generates this directory during the compilation of a package. " + - "\n# It contains compiler-generated artifacts and the final executable if this is an application " + - "package.\ntarget/\n" + - "\n" + - "# Ballerina maintains the compiler-generated source code here.\n" + - "# Remove this if you want to commit generated sources.\n" + - "generated/\n" + - "\n" + - "# Contains configuration values used during development time.\n" + - "# See https://ballerina.io/learn/provide-values-to-configurable-variables/ for more details.\n" + - "Config.toml\n"; + String expectedGitignoreContent = """ + # Ballerina generates this directory during the compilation of a package. + # It contains compiler-generated artifacts and the final executable if this is an application package. + target/ + + # Ballerina maintains the compiler-generated source code here. + # Remove this if you want to commit generated sources. + generated/ + + # Contains configuration values used during development time. + # See https://ballerina.io/learn/provide-values-to-configurable-variables/ for more details. + Config.toml + """; Assert.assertEquals(gitignoreContent.trim(), expectedGitignoreContent.trim()); Assert.assertTrue(readOutput().contains("Created new package")); @@ -403,7 +413,7 @@ public void testNewCommandWithRelativePath() throws IOException { packagePath = ".\\relative_project_name"; } String[] args = {packagePath}; - Path packageDir = Paths.get(packagePath); + Path packageDir = Path.of(packagePath); NewCommand newCommand = new NewCommand(printStream, false); new CommandLine(newCommand).parseArgs(args); newCommand.execute(); @@ -412,11 +422,11 @@ public void testNewCommandWithRelativePath() throws IOException { // - Ballerina.toml // - main.bal - Path currentDir = Paths.get(System.getProperty(ProjectConstants.USER_DIR)); - Path relativeToCurrentDir = Paths.get(currentDir.toString(), packagePath).normalize(); + Path currentDir = Path.of(System.getProperty(ProjectConstants.USER_DIR)); + Path relativeToCurrentDir = Path.of(currentDir.toString(), packagePath).normalize(); Assert.assertTrue(Files.exists(relativeToCurrentDir)); Assert.assertTrue(Files.exists(relativeToCurrentDir.resolve(ProjectConstants.BALLERINA_TOML))); - String name = Paths.get(args[0]).getFileName().toString(); + String name = Path.of(args[0]).getFileName().toString(); String tomlContent = Files.readString( relativeToCurrentDir.resolve(ProjectConstants.BALLERINA_TOML), StandardCharsets.UTF_8); String expectedContent = "[package]\n" + @@ -433,17 +443,19 @@ public void testNewCommandWithRelativePath() throws IOException { Assert.assertTrue(Files.exists(relativeToCurrentDir.resolve(ProjectConstants.GITIGNORE_FILE_NAME))); String gitignoreContent = Files.readString( relativeToCurrentDir.resolve(ProjectConstants.GITIGNORE_FILE_NAME), StandardCharsets.UTF_8); - String expectedGitignoreContent = "# Ballerina generates this directory during the compilation of a package. " + - "\n# It contains compiler-generated artifacts and the final executable if this is an application " + - "package.\ntarget/\n" + - "\n" + - "# Ballerina maintains the compiler-generated source code here.\n" + - "# Remove this if you want to commit generated sources.\n" + - "generated/\n" + - "\n" + - "# Contains configuration values used during development time.\n" + - "# See https://ballerina.io/learn/provide-values-to-configurable-variables/ for more details.\n" + - "Config.toml\n"; + String expectedGitignoreContent = """ + # Ballerina generates this directory during the compilation of a package. + # It contains compiler-generated artifacts and the final executable if this is an application package. + target/ + + # Ballerina maintains the compiler-generated source code here. + # Remove this if you want to commit generated sources. + generated/ + + # Contains configuration values used during development time. + # See https://ballerina.io/learn/provide-values-to-configurable-variables/ for more details. + Config.toml + """; Assert.assertEquals(gitignoreContent.trim(), expectedGitignoreContent.trim()); Assert.assertTrue(readOutput().contains("Created new package")); @@ -470,7 +482,7 @@ public void testNewCommandWithMain(String packagePath) throws IOException { Assert.assertTrue(Files.exists(packageDir)); Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.BALLERINA_TOML))); - String packageName = Paths.get(args[0]).getFileName().toString(); + String packageName = Path.of(args[0]).getFileName().toString(); String tomlContent = Files.readString( packageDir.resolve(ProjectConstants.BALLERINA_TOML), StandardCharsets.UTF_8); String expectedContent = "[package]\n" + @@ -513,8 +525,10 @@ public void testNewCommandWithService(String packagePath) throws IOException { Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.BALLERINA_TOML))); String tomlContent = Files.readString( packageDir.resolve(ProjectConstants.BALLERINA_TOML), StandardCharsets.UTF_8); - String expectedContent = "[build-options]\n" + - "observabilityIncluded = true\n"; + String expectedContent = """ + [build-options] + observabilityIncluded = true + """; Assert.assertTrue(tomlContent.contains(expectedContent)); Assert.assertTrue(Files.exists(packageDir.resolve("service.bal"))); @@ -552,7 +566,7 @@ public void testNewCommandWithLib(String packagePath) throws IOException { String tomlContent = Files.readString( packageDir.resolve(ProjectConstants.BALLERINA_TOML), StandardCharsets.UTF_8); - String packageName = Paths.get(args[0]).getFileName().toString(); + String packageName = Path.of(args[0]).getFileName().toString(); String expectedTomlContent = "[package]\n" + "org = \"" + System.getProperty("user.name").replaceAll("[^a-zA-Z0-9_]", "_") + "\"\n" + "name = \"" + packageName + "\"\n" + @@ -563,7 +577,6 @@ public void testNewCommandWithLib(String packagePath) throws IOException { Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.PACKAGE_MD_FILE_NAME))); Assert.assertTrue(Files.exists(packageDir.resolve(packageName + ".bal"))); Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.TEST_DIR_NAME))); - Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.RESOURCE_DIR_NAME))); Assert.assertTrue(readOutput().contains("Created new package")); } @@ -587,7 +600,7 @@ public void testNewCommandWithTool() throws IOException { Assert.assertTrue(Files.exists(packageDir)); Assert.assertTrue(Files.isDirectory(packageDir)); Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.BALLERINA_TOML))); - String packageName = Paths.get(args[0]).getFileName().toString(); + String packageName = Path.of(args[0]).getFileName().toString(); String tomlContent = Files.readString( packageDir.resolve(ProjectConstants.BALLERINA_TOML), StandardCharsets.UTF_8); String expectedContent = "[package]\n" + @@ -622,7 +635,7 @@ public void testNewCommandWithTool() throws IOException { errStream.println(e.getDetailedMessages().toString()); } String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-tool-template.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-tool-template.txt")); Assert.assertTrue(packageDir.resolve("target").resolve("bin").resolve("tool_sample.jar") .toFile().exists()); @@ -637,7 +650,7 @@ public void testNewCommandWithTool() throws IOException { packCommand.execute(); String packBuildLog = readOutput(true); - Assert.assertEquals(packBuildLog.replaceAll("\r", ""), getOutput("pack-tool-template.txt")); + Assert.assertEquals(packBuildLog.replace("\r", ""), getOutput("pack-tool-template.txt")); Assert.assertTrue( packageDir.resolve("target").resolve("bala") .resolve("testuserorg-tool_sample-java17-0.1.0.bala").toFile().exists()); @@ -654,7 +667,7 @@ public void testNewCommandWithInvalidProjectName(String projectName, String deri Assert.assertTrue(Files.exists(packageDir)); Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.BALLERINA_TOML))); Assert.assertTrue(Files.exists(packageDir.resolve("main.bal"))); - String buildOutput = readOutput().replaceAll("\r", ""); + String buildOutput = readOutput().replace("\r", ""); Assert.assertEquals(buildOutput, "Package name is derived as '" + derivedPkgName + "'. " + "Edit the Ballerina.toml to change it.\n\n" + "Created new package '" + derivedPkgName + "' at " + packageDir + ".\n"); @@ -726,7 +739,7 @@ public void testNewCommandWithToolTemplateCentral() throws IOException { new CommandLine(packCommand).parseArgs(); packCommand.execute(); String packBuildLog = readOutput(true); - Assert.assertEquals(packBuildLog.replaceAll("\r", ""), getOutput("pack-central-tool.txt")); + Assert.assertEquals(packBuildLog.replace("\r", ""), getOutput("pack-central-tool.txt")); Assert.assertTrue( packageDir.resolve("target").resolve("bala") .resolve("testorg-sample_tool_template-java17-1.0.0.bala").toFile().exists()); @@ -743,24 +756,27 @@ public void testNewCommandWithProvidedTemplateCentral() throws IOException { newCommand.execute(); Assert.assertTrue(Files.exists(packageDir)); Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.BALLERINA_TOML))); - String expectedTomlContent = "[package]\n" + - "org = \"testorg\"\n" + - "name = \"sample_provided_template\"\n" + - "version = \"1.0.0\"\n" + - "export = [\"sample_provided_template\"]\n" + - "distribution = \"2201.9.0-SNAPSHOT\"\n" + - "\n" + - "[build-options]\n" + - "observabilityIncluded = true\n" + - "\n" + - "[[platform.java17.dependency]]\n" + - "artifactId = \"project1\"\n" + - "groupId = \"com.example\"\n" + - "version = \"1.0\"\n" + - "scope = \"provided\"\n"; + String expectedTomlContent = """ + [package] + org = "testorg" + name = "sample_provided_template" + version = "1.0.0" + export = ["sample_provided_template"] + distribution = "2201.9.0-SNAPSHOT" + + [build-options] + observabilityIncluded = true + + [[platform.java17.dependency]] + artifactId = "project1" + groupId = "com.example" + version = "1.0" + scope = "provided" + """; Assert.assertEquals( readFileAsString(packageDir.resolve(ProjectConstants.BALLERINA_TOML)), expectedTomlContent); - Assert.assertTrue(readOutput().contains("WARNING: path for the platform dependency project1 with provided " + + Assert.assertTrue(readOutput().replace("\r", "").contains( + "WARNING: path for the platform dependency project1 with provided " + "scope should be specified in the Ballerina.toml\n" + "Created new package 'sample_provided_template'")); } @@ -778,14 +794,17 @@ public void testNewCommandWithTemplateInLocalCache() throws IOException { Assert.assertTrue(Files.exists(packageDir)); Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.BALLERINA_TOML))); - String expectedTomlContent = "[package]\n" + - "org = \"admin\"\n" + - "name = \"sample_pull_local\"\n" + - "version = \"0.1.5\"\n" + - "export = [\"sample_pull_local\"]\n" + - "distribution = \"slbeta4\"\n" + - "\n[build-options]\n" + - "observabilityIncluded = true\n"; + String expectedTomlContent = """ + [package] + org = "admin" + name = "sample_pull_local" + version = "0.1.5" + export = ["sample_pull_local"] + distribution = "slbeta4" + + [build-options] + observabilityIncluded = true + """; Assert.assertEquals( readFileAsString(packageDir.resolve(ProjectConstants.BALLERINA_TOML)), expectedTomlContent); @@ -808,14 +827,17 @@ public void testNewCommandWithTemplateCentralPullWithoutVersion() throws IOExcep Assert.assertTrue(Files.exists(packageDir)); Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.BALLERINA_TOML))); - String expectedTomlContent = "[package]\n" + - "org = \"parkavik\"\n" + - "name = \"sample_pull_WO_Module_Version\"\n" + - "version = \"1.0.1\"\n" + - "export = [\"sample_pull_WO_Module_Version\"]\n" + - "distribution = \"slbeta4\"\n" + - "\n[build-options]\n" + - "observabilityIncluded = true\n"; + String expectedTomlContent = """ + [package] + org = "parkavik" + name = "sample_pull_WO_Module_Version" + version = "1.0.1" + export = ["sample_pull_WO_Module_Version"] + distribution = "slbeta4" + + [build-options] + observabilityIncluded = true + """; Assert.assertEquals( readFileAsString(packageDir.resolve(ProjectConstants.BALLERINA_TOML)), expectedTomlContent); Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.PACKAGE_MD_FILE_NAME))); @@ -837,14 +859,17 @@ public void testNewCommandWithTemplateCentralPullWithVersion() throws IOExceptio Assert.assertTrue(Files.exists(packageDir)); Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.BALLERINA_TOML))); - String expectedTomlContent = "[package]\n" + - "org = \"parkavik\"\n" + - "name = \"sample_pull\"\n" + - "version = \"1.0.0\"\n" + - "export = [\"sample_pull\"]\n" + - "distribution = \"slbeta4\"\n" + - "\n[build-options]\n" + - "observabilityIncluded = true\n"; + String expectedTomlContent = """ + [package] + org = "parkavik" + name = "sample_pull" + version = "1.0.0" + export = ["sample_pull"] + distribution = "slbeta4" + + [build-options] + observabilityIncluded = true + """; Assert.assertEquals( readFileAsString(packageDir.resolve(ProjectConstants.BALLERINA_TOML)), expectedTomlContent); Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.PACKAGE_MD_FILE_NAME))); @@ -854,6 +879,9 @@ public void testNewCommandWithTemplateCentralPullWithVersion() throws IOExceptio @Test(description = "Test pulling a central template and replacing the template name in module imports") public void testNewCommandCentralTemplateReplaceImports() throws IOException { + if (isWindows()) { + throw new SkipException("Not working on Windows"); + } String templateArg = "testorg/centralSample:1.0.2"; String packageName = "central_sample"; Path packageDir = tmpDir.resolve(packageName); @@ -965,16 +993,18 @@ public void testNewCommandCentralPullWithPlatformDependencies() throws IOExcepti String tomlContent = Files.readString( packageDir.resolve(ProjectConstants.BALLERINA_TOML), StandardCharsets.UTF_8); - String expectedTomlPkgContent = "[package]\n" + - "org = \"admin\"\n" + - "name = \"sample_pull_libs\"\n" + - "version = \"0.1.0\"\n" + - "export = [\"sample_pull_libs\"]\n" + - "distribution = \"slbeta4\"\n"; - String expectedTomlLibContent = - "artifactId = \"snakeyaml\"\n" + - "groupId = \"org.yaml\"\n" + - "version = \"2.0\""; + String expectedTomlPkgContent = """ + [package] + org = "admin" + name = "sample_pull_libs" + version = "0.1.0" + export = ["sample_pull_libs"] + distribution = "slbeta4" + """; + String expectedTomlLibContent = """ + artifactId = "snakeyaml" + groupId = "org.yaml" + version = "2.0\""""; Assert.assertTrue(tomlContent.contains(expectedTomlPkgContent)); Assert.assertTrue(tomlContent.contains(expectedTomlLibContent)); @@ -1013,10 +1043,11 @@ public void testNewCommandCentralPullWithCentralDependency() throws IOException Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.BALLERINA_TOML))); String depsTomlContent = Files.readString( packageDir.resolve(ProjectConstants.DEPENDENCIES_TOML), StandardCharsets.UTF_8); - Assert.assertTrue(depsTomlContent.contains("[[package]]\n" + - "org = \"pramodya\"\n" + - "name = \"winery\"\n" + - "version = \"0.1.0\"")); + Assert.assertTrue(depsTomlContent.contains(""" + [[package]] + org = "pramodya" + name = "winery" + version = "0.1.0\"""")); } @Test(description = "Test new command by pulling a central template that has simple include patterns") public void testNewCommandTemplateWithSimpleIncludePatterns() throws IOException { @@ -1140,7 +1171,7 @@ public void testNewCommandNoArgs() throws IOException { // Test if no arguments was passed in String[] args = {}; NewCommand newCommand = new NewCommand(printStream, false); - new CommandLine(newCommand).parse(args); + new CommandLine(newCommand).parseArgs(args); newCommand.execute(); Assert.assertTrue(readOutput().contains("project path is not provided")); @@ -1153,7 +1184,7 @@ public void testNewCommandMultipleArgs() throws IOException { Path packageDir2 = tmpDir.resolve("sample3"); String[] args = {packageDir1.toString(), packageDir2.toString()}; NewCommand newCommand = new NewCommand(printStream, false); - new CommandLine(newCommand).parse(args); + new CommandLine(newCommand).parseArgs(args); newCommand.execute(); Assert.assertTrue(readOutput().contains("too many arguments")); @@ -1165,7 +1196,7 @@ public void testNewCommandArgAndHelp() throws IOException { Path packageDir = tmpDir.resolve("sample2"); String[] args = {packageDir.toString(), "--help"}; NewCommand newCommand = new NewCommand(printStream, false); - new CommandLine(newCommand).parse(args); + new CommandLine(newCommand).parseArgs(args); newCommand.execute(); Assert.assertTrue(readOutput().contains("ballerina-new - Create a new Ballerina package")); @@ -1176,7 +1207,7 @@ public void testNewCommandWithHelp() throws IOException { // Test if no arguments was passed in String[] args = {"-h"}; NewCommand newCommand = new NewCommand(printStream, false); - new CommandLine(newCommand).parse(args); + new CommandLine(newCommand).parseArgs(args); newCommand.execute(); Assert.assertTrue(readOutput().contains("ballerina-new - Create a new Ballerina package")); @@ -1188,7 +1219,7 @@ public void testNewCommandInsideProject() throws IOException { Path parentDir = tmpDir.resolve("parent"); String[] args = {parentDir.toString()}; NewCommand newCommand = new NewCommand(printStream, false); - new CommandLine(newCommand).parse(args); + new CommandLine(newCommand).parseArgs(args); newCommand.execute(); readOutput(true); @@ -1197,7 +1228,7 @@ public void testNewCommandInsideProject() throws IOException { Path subDir = parentDir.resolve("subdir"); String[] args2 = {subDir.toString()}; newCommand = new NewCommand(printStream, false); - new CommandLine(newCommand).parse(args2); + new CommandLine(newCommand).parseArgs(args2); newCommand.execute(); Assert.assertFalse(readOutput().contains("directory is already a ballerina project.")); @@ -1211,7 +1242,7 @@ public void testNewCommandWithinProject() throws IOException { Files.createDirectory(parentPath); String[] args = {parentPath.resolve("sample").toString()}; NewCommand newCommand = new NewCommand(printStream, false); - new CommandLine(newCommand).parse(args); + new CommandLine(newCommand).parseArgs(args); newCommand.execute(); Assert.assertFalse(readOutput().contains("directory is already within a ballerina project.")); @@ -1230,7 +1261,7 @@ public void testNewCommandWithInvalidLengthPackageName() throws IOException { Path packageDir = tmpDir.resolve(longPkgName); String[] args = {packageDir.toString()}; NewCommand newCommand = new NewCommand(printStream, false); - new CommandLine(newCommand).parse(args); + new CommandLine(newCommand).parseArgs(args); newCommand.execute(); Assert.assertTrue(readOutput().contains("invalid package name : '" + longPkgName + "' :\n" @@ -1257,7 +1288,7 @@ public void testNewCommandWithInvalidPackageNames1(String packageName, String ou String buildLog = readOutput(); String outLog = getOutput(outputLog); String replacedOutLog = outLog.replace(packageName, args[0]); - Assert.assertEquals(buildLog.replaceAll("\r", ""), replacedOutLog); + Assert.assertEquals(buildLog.replace("\r", ""), replacedOutLog); } @DataProvider(name = "PackageNameHasOnlyNonAlphanumeric") @@ -1279,16 +1310,16 @@ public void testNewCommandWithPackageNameHasOnlyNonAlphanumeric(String pkgName, Assert.assertTrue(Files.exists(packageDir)); Assert.assertTrue(Files.exists(packageDir.resolve(ProjectConstants.BALLERINA_TOML))); Assert.assertTrue(Files.exists(packageDir.resolve("main.bal"))); - String buildOutput = readOutput().replaceAll("\r", ""); + String buildOutput = readOutput().replace("\r", ""); Assert.assertEquals(buildOutput, "Package name is derived as '" + derivedPkgName + "'. " + "Edit the Ballerina.toml to change it.\n\n" + "Created new package '" + derivedPkgName + "' at " + packageDir + ".\n"); } static class Copy extends SimpleFileVisitor { - private Path fromPath; - private Path toPath; - private StandardCopyOption copyOption; + private final Path fromPath; + private final Path toPath; + private final StandardCopyOption copyOption; public Copy(Path fromPath, Path toPath, StandardCopyOption copyOption) { diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/PackCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/PackCommandTest.java index ddbc99ac4731..f35c317e27c2 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/PackCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/PackCommandTest.java @@ -1,8 +1,11 @@ package io.ballerina.cli.cmd; import io.ballerina.cli.launcher.BLauncherException; +import io.ballerina.projects.util.BuildToolUtils; import io.ballerina.projects.util.ProjectUtils; import org.ballerinalang.test.BCompileUtil; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -16,14 +19,16 @@ import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; +import java.util.List; import java.util.Objects; import static io.ballerina.cli.cmd.CommandOutputUtils.assertTomlFilesEquals; import static io.ballerina.cli.cmd.CommandOutputUtils.getOutput; import static io.ballerina.cli.cmd.CommandOutputUtils.replaceDependenciesTomlContent; import static io.ballerina.projects.util.ProjectConstants.DEPENDENCIES_TOML; +import static io.ballerina.projects.util.ProjectConstants.DIST_CACHE_DIRECTORY; import static io.ballerina.projects.util.ProjectConstants.RESOURCE_DIR_NAME; +import static io.ballerina.projects.util.ProjectConstants.USER_DIR; import static io.ballerina.projects.util.ProjectConstants.USER_DIR_PROPERTY; /** @@ -36,9 +41,10 @@ public class PackCommandTest extends BaseCommandTest { private static final String VALID_PROJECT = "validApplicationProject"; private Path testResources; - static Path logFile = Paths.get("./src/test/resources/compiler_plugin_tests/" + - "log_creator_combined_plugin/compiler-plugin.txt"); + private static final Path logFile = Path.of("build/logs/log_creator_combined_plugin/compiler-plugin.txt") + .toAbsolutePath(); + @Override @BeforeClass public void setup() throws IOException { super.setup(); @@ -46,12 +52,12 @@ public void setup() throws IOException { this.testResources = super.tmpDir.resolve("build-test-resources"); URI testResourcesURI = Objects.requireNonNull(getClass().getClassLoader().getResource("test-resources")) .toURI(); - Path testResourcesPath = Paths.get(testResourcesURI); + Path testResourcesPath = Path.of(testResourcesURI); Files.walkFileTree(testResourcesPath, new BuildCommandTest.Copy(testResourcesPath, this.testResources)); // Copy the compiler plugin jars to the test resources directory - Path compilerPluginJarsPath = Paths.get("build", "compiler-plugin-jars"); + Path compilerPluginJarsPath = Path.of("build", "compiler-plugin-jars"); Files.walkFileTree(compilerPluginJarsPath, new BuildCommandTest.Copy(compilerPluginJarsPath, this.testResources.resolve("compiler-plugin-jars"))); @@ -62,32 +68,18 @@ public void setup() throws IOException { Files.writeString(logFile, ""); } - @Test(description = "Test package command") - public void testPackCommand() throws IOException { - Path projectPath = this.testResources.resolve(VALID_PROJECT); - System.setProperty("user.dir", projectPath.toString()); - - PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); - new CommandLine(packCommand).parseArgs(); - packCommand.execute(); - String buildLog = readOutput(true); - - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("compile-bal-project.txt")); - Assert.assertTrue( - projectPath.resolve("target").resolve("bala").resolve("foo-winery-any-0.1.0.bala").toFile().exists()); - } - - @Test(description = "Pack a library package") - public void testPackProject() throws IOException { + @Test(description = "Pack a library package", dataProvider = "optimizeDependencyCompilation") + public void testPackProject(Boolean optimizeDependencyCompilation) throws IOException { Path projectPath = this.testResources.resolve("validLibraryProject"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); - PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); + PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true, + optimizeDependencyCompilation); new CommandLine(packCommand).parseArgs(); packCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("compile-bal-project.txt")); Assert.assertTrue( projectPath.resolve("target").resolve("bala").resolve("foo-winery-any-0.1.0.bala").toFile().exists()); @@ -96,19 +88,21 @@ public void testPackProject() throws IOException { .resolve("foo-winery-0.1.0.jar").toFile().exists()); } - @Test(description = "Pack a ballerina project with the engagement of all type of compiler plugins") - public void testRunBalProjectWithAllCompilerPlugins() throws IOException { - Path compilerPluginPath = Paths.get("./src/test/resources/test-resources/compiler-plugins"); + @Test(description = "Pack a ballerina project with the engagement of all type of compiler plugins", + dataProvider = "optimizeDependencyCompilation") + public void testRunBalProjectWithAllCompilerPlugins(Boolean optimizeDependencyCompilation) throws IOException { + Path compilerPluginPath = Path.of("./src/test/resources/test-resources/compiler-plugins"); BCompileUtil.compileAndCacheBala(compilerPluginPath.resolve("log_creator_pkg_provided_code_analyzer_im") - .toAbsolutePath().toString()); + .toAbsolutePath().toString()); BCompileUtil.compileAndCacheBala(compilerPluginPath.resolve("log_creator_pkg_provided_code_generator_im") .toAbsolutePath().toString()); BCompileUtil.compileAndCacheBala(compilerPluginPath.resolve("log_creator_pkg_provided_code_modifier_im") .toAbsolutePath().toString()); Path projectPath = this.testResources.resolve("compiler-plugins").resolve("log_creator_combined_plugin"); - System.setProperty("user.dir", projectPath.toString()); - PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); + System.setProperty(USER_DIR, projectPath.toString()); + PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true, + optimizeDependencyCompilation); new CommandLine(packCommand).parseArgs(); packCommand.execute(); String logFileContent = Files.readString(logFile); @@ -141,7 +135,7 @@ public void testRunBalProjectWithAllCompilerPlugins() throws IOException { @Test(description = "Pack an application package") public void testPackApplicationPackage() { Path projectPath = this.testResources.resolve("validApplicationProject"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); new CommandLine(packCommand).parseArgs(); try { @@ -155,24 +149,25 @@ public void testPackApplicationPackage() { @Test(description = "Pack a Standalone Ballerina file") public void testPackStandaloneFile() throws IOException { Path projectPath = this.testResources.resolve("valid-bal-file").resolve("hello_world.bal"); - System.setProperty("user.dir", this.testResources.resolve("valid-bal-file").toString()); - PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); + System.setProperty(USER_DIR, this.testResources.resolve("valid-bal-file").toString()); + PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true, false); new CommandLine(packCommand).parseArgs(); packCommand.execute(); String buildLog = readOutput(true); Assert.assertTrue(buildLog.contains(" bal pack can only be used with a Ballerina package.")); } - @Test(description = "Pack a package with platform libs") - public void testPackageWithPlatformLibs() throws IOException { + @Test(description = "Pack a package with platform libs", dataProvider = "optimizeDependencyCompilation") + public void testPackageWithPlatformLibs(Boolean optimizeDependencyCompilation) throws IOException { Path projectPath = this.testResources.resolve("validGraalvmCompatibleProjectWithPlatformLibs"); - System.setProperty("user.dir", projectPath.toString()); - PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); + System.setProperty(USER_DIR, projectPath.toString()); + PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true, + optimizeDependencyCompilation); new CommandLine(packCommand).parseArgs(); packCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-project-with-platform-libs.txt")); Assert.assertTrue(projectPath.resolve("target").resolve("bala").resolve("sameera-myproject-java17-0.1.0.bala") .toFile().exists()); @@ -181,13 +176,13 @@ public void testPackageWithPlatformLibs() throws IOException { @Test(description = "Pack a package with java11 platform libs") public void testPackageWithJava11PlatformLibs() throws IOException { Path projectPath = this.testResources.resolve("projectWithJava11PlatformLibs"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); new CommandLine(packCommand).parseArgs(); packCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-project-with-platform-libs.txt")); Path balaDirPath = projectPath.resolve("target").resolve("bala"); Assert.assertTrue(balaDirPath.resolve("sameera-myproject-java17-0.1.0.bala") @@ -202,13 +197,13 @@ public void testPackageWithJava11PlatformLibs() throws IOException { @Test(description = "Pack a package with java11 and java17 platform libs") public void testPackageWithJava11andJava17PlatformLibs() throws IOException { Path projectPath = this.testResources.resolve("projectWithJava11and17PlatformLibs"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); new CommandLine(packCommand).parseArgs(); packCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-project-with-platform-libs.txt")); Path balaDirPath = projectPath.resolve("target").resolve("bala"); Assert.assertTrue(balaDirPath.resolve("sameera-myproject-java17-0.1.0.bala") @@ -225,13 +220,13 @@ public void testPackageWithJava11andJava17PlatformLibs() throws IOException { @Test(description = "Pack a package with testOnly platform libs") public void testPackageWithTestOnlyPlatformLibs() throws IOException { Path projectPath = this.testResources.resolve("projectWithTestOnlyPlatformLibs"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); new CommandLine(packCommand).parseArgs(); packCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("pack-project-with-test-only-platform-libs.txt")); Assert.assertTrue(projectPath.resolve("target").resolve("bala").resolve("sameera-myproject-any-0.1.0.bala") .toFile().exists()); @@ -240,42 +235,45 @@ public void testPackageWithTestOnlyPlatformLibs() throws IOException { @Test(description = "Pack a package with ballerina/java imports only in tests") public void testPackageWithTestOnlyJavaImports() throws IOException { Path projectPath = this.testResources.resolve("projectWithTestOnlyJavaImports"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); new CommandLine(packCommand).parseArgs(); packCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("pack-project-with-test-only-platform-libs.txt")); Assert.assertTrue(projectPath.resolve("target").resolve("bala").resolve("sameera-myproject-any-0.1.0.bala") .toFile().exists()); } - @Test(description = "Pack a project with a build tool execution") - public void testPackProjectWithBuildTool() throws IOException { + @Test(description = "Pack a project with a build tool execution", dataProvider = "optimizeDependencyCompilation") + public void testPackProjectWithBuildTool(Boolean optimizeDependencyCompilation) throws IOException { Path projectPath = this.testResources.resolve("proper-build-tool"); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); + PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true, + optimizeDependencyCompilation); new CommandLine(packCommand).parseArgs(); packCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", "").replace("\\", "/"), getOutput("pack-project-with-build-tool.txt")); Assert.assertTrue(projectPath.resolve("target").resolve("bala").resolve("foo-winery-any-0.1.0.bala") .toFile().exists()); } - @Test(description = "Pack a package with an empty Dependencies.toml") - public void testPackageWithEmptyDependenciesToml() throws IOException { + @Test(description = "Pack a package with an empty Dependencies.toml", + dataProvider = "optimizeDependencyCompilation") + public void testPackageWithEmptyDependenciesToml(Boolean optimizeDependencyCompilation) throws IOException { Path projectPath = this.testResources.resolve("validProjectWithDependenciesToml"); - System.setProperty("user.dir", projectPath.toString()); - PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); + System.setProperty(USER_DIR, projectPath.toString()); + PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true, + optimizeDependencyCompilation); new CommandLine(packCommand).parseArgs(); packCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-project-with-dependencies-toml.txt")); Assert.assertTrue(projectPath.resolve("target").resolve("bala").resolve("foo-winery-any-0.1.0.bala") .toFile().exists()); @@ -287,15 +285,16 @@ public void testPackageWithEmptyDependenciesToml() throws IOException { } @Test(description = "Pack a package without root package in Dependencies.toml") - public void testPackageWithoutRootPackageInDependenciesToml() throws IOException { + public void testPackageWithoutRootPackageInDependenciesToml() + throws IOException { Path projectPath = this.testResources.resolve("validProjectWoRootPkgInDepsToml"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); new CommandLine(packCommand).parseArgs(); packCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-project-wo-root-pkg-in-deps-toml.txt")); Assert.assertTrue(projectPath.resolve("target").resolve("bala").resolve("foo-winery-java17-0.1.0.bala") .toFile().exists()); @@ -307,7 +306,7 @@ public void testPackageWithoutRootPackageInDependenciesToml() throws IOException @Test(description = "Pack an empty package with compiler plugin") public void testPackEmptyProjectWithCompilerPlugin() throws IOException { Path projectPath = this.testResources.resolve("emptyProjectWithCompilerPlugin"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); new CommandLine(packCommand).parseArgs(); @@ -316,14 +315,35 @@ public void testPackEmptyProjectWithCompilerPlugin() throws IOException { Assert.assertTrue(projectPath.resolve("target").resolve("bala") .resolve("wso2-emptyProjWithCompilerPlugin-java17-0.1.0.bala").toFile().exists()); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("compile-empty-project-with-compiler-plugin.txt")); } + @Test(description = "Pack an empty package with compiler plugin") + public void testPackEmptyProjectWithBuildTools() throws IOException { + Path testDistCacheDirectory = Path.of("build").toAbsolutePath().resolve(DIST_CACHE_DIRECTORY); + BCompileUtil.compileAndCacheBala(testResources.resolve("buildToolResources").resolve("tools") + .resolve("ballerina-generate-file").toString(), testDistCacheDirectory); + Path projectPath = this.testResources.resolve("emptyProjectWithBuildTool"); + replaceDependenciesTomlContent(projectPath, "**INSERT_DISTRIBUTION_VERSION_HERE**", + RepoUtils.getBallerinaShortVersion()); + System.setProperty(USER_DIR, projectPath.toString()); + try (MockedStatic repoUtils = Mockito.mockStatic( + BuildToolUtils.class, Mockito.CALLS_REAL_METHODS)) { + repoUtils.when(BuildToolUtils::getCentralBalaDirPath).thenReturn(testDistCacheDirectory.resolve("bala")); + PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); + new CommandLine(packCommand).parseArgs(); + packCommand.execute(); + } + String buildLog = readOutput(true); + Assert.assertEquals(buildLog.replace("\r", "").replace("\\", "/"), + getOutput("pack-empty-project-with-build-tools.txt")); + } + @Test(description = "Pack an empty package as a tool") public void testPackEmptyProjectWithTool() throws IOException { Path projectPath = this.testResources.resolve("emptyProjectWithTool"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); new CommandLine(packCommand).parseArgs(); @@ -332,14 +352,14 @@ public void testPackEmptyProjectWithTool() throws IOException { Assert.assertTrue(projectPath.resolve("target").resolve("bala") .resolve("wso2-emptyProjWithTool-java17-0.1.0.bala").toFile().exists()); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("compile-empty-project-with-tool.txt")); } @Test(description = "Pack an empty package with tests only") public void testPackEmptyProjectWithTestsOnly() { Path projectPath = this.testResources.resolve("emptyProjectWithTestsOnly"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); new CommandLine(packCommand).parseArgs(); @@ -352,7 +372,7 @@ public void testPackEmptyProjectWithTestsOnly() { @Test(description = "Pack an empty package with Non Default modules") public void testPackEmptyProjectWithNonDefaultModules() { Path projectPath = this.testResources.resolve("emptyProjectWithNonDefaultModules"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); new CommandLine(packCommand).parseArgs(); @@ -365,7 +385,7 @@ public void testPackEmptyProjectWithNonDefaultModules() { @Test(description = "Pack an empty package with Non Default modules with Tests only") public void testPackEmptyProjectWithNonDefaultModulesTestOnly() { Path projectPath = this.testResources.resolve("emptyProjectWithNonDefaultModulesTestOnly"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); new CommandLine(packCommand).parseArgs(); @@ -378,14 +398,17 @@ public void testPackEmptyProjectWithNonDefaultModulesTestOnly() { @Test(description = "Pack an empty package with empty Non Default") public void testPackEmptyNonDefaultModule() throws IOException { Path projectPath = this.testResources.resolve("emptyNonDefaultModule"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); new CommandLine(packCommand).parseArgs(); - packCommand.execute(); - String buildLog = readOutput(true); - - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-empty-nondefault-module.txt")); + try { + packCommand.execute(); + } catch (BLauncherException e) { + List messages = e.getMessages(); + Assert.assertEquals(messages.size(), 1); + Assert.assertEquals(messages.get(0), getOutput("build-empty-nondefault-module.txt")); + } Assert.assertFalse(projectPath.resolve("target").resolve("bala") .resolve("wso2-emptyNonDefaultModule-any-0.1.0.bala").toFile().exists()); } @@ -394,7 +417,7 @@ public void testPackEmptyNonDefaultModule() throws IOException { public void testCustomTargetDir() throws IOException { Path projectPath = this.testResources.resolve(VALID_PROJECT); Path customTargetDir = projectPath.resolve("customTargetDir"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true, customTargetDir); @@ -402,7 +425,7 @@ public void testCustomTargetDir() throws IOException { packCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("pack-bal-project-custom-dir.txt")); Assert.assertFalse(Files.exists(customTargetDir.resolve("bin"))); Assert.assertTrue(Files.exists(customTargetDir.resolve("cache"))); @@ -415,7 +438,7 @@ public void testCustomTargetDir() throws IOException { public void testCustomTargetDirWithRelativePath() throws IOException { Path projectPath = this.testResources.resolve(VALID_PROJECT); Path customTargetDir = projectPath.resolve("./customTargetDir"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true, customTargetDir); @@ -423,7 +446,7 @@ public void testCustomTargetDirWithRelativePath() throws IOException { packCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("pack-bal-project-custom-dir.txt")); Assert.assertFalse(Files.exists(customTargetDir.resolve("bin"))); Assert.assertTrue(Files.exists(customTargetDir.resolve("cache"))); @@ -435,15 +458,17 @@ public void testCustomTargetDirWithRelativePath() throws IOException { @Test(description = "Pack an empty package") public void testPackEmptyPackage() throws IOException { Path projectPath = this.testResources.resolve("emptyPackage"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); new CommandLine(packCommand).parseArgs(); - packCommand.execute(); - - String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), - getOutput("pack-empty-package.txt")); + try { + packCommand.execute(); + } catch (BLauncherException e) { + List messages = e.getMessages(); + Assert.assertEquals(messages.size(), 1); + Assert.assertEquals(messages.get(0), getOutput("pack-empty-package.txt")); + } } @Test(description = "Pack an empty package with compiler plugin") @@ -451,14 +476,14 @@ public void testPackEmptyPackageWithCompilerPlugin() throws IOException { Path projectPath = this.testResources.resolve("emptyPackageWithCompilerPlugin"); replaceDependenciesTomlContent( projectPath, "**INSERT_DISTRIBUTION_VERSION_HERE**", RepoUtils.getBallerinaShortVersion()); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); new CommandLine(packCommand).parseArgs(); packCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("pack-empty-package-with-compiler-plugin.txt")); } @@ -476,7 +501,7 @@ public void testPackNonTemplatePackageWithACompilerPackageDependency() throws IO // BALA should contain the source documents modified by the compiler plugin Path projectPath = this.testResources.resolve("projects-using-compiler-plugins") .resolve("package_plugin_code_modify_user_not_template"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); new CommandLine(packCommand).parseArgs(); @@ -501,7 +526,7 @@ public void testPackTemplatePackageWithACompilerPackageDependency() throws IOExc // BALA should contain the original source documents and not documents modified by the compiler plugin Path projectPath = this.testResources.resolve("projects-using-compiler-plugins") .resolve("package_plugin_code_modify_user_template"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); new CommandLine(packCommand).parseArgs(); @@ -522,13 +547,149 @@ public void testPackTemplatePackageWithACompilerPackageDependency() throws IOExc @Test(description = "Pack a library package with platform libraries") public void testPackProjectWithPlatformLibs() throws IOException { Path projectPath = this.testResources.resolve("validProjectWithPlatformLibs1"); - System.setProperty("user.dir", projectPath.toString()); + System.setProperty(USER_DIR, projectPath.toString()); + + PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); + new CommandLine(packCommand).parseArgs(); + packCommand.execute(); + String buildLog = readOutput(true); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("pack-project-with-platform-libs.txt")); + Path balaDirPath = projectPath.resolve("target").resolve("bala"); + Path balaFilePath = balaDirPath.resolve("sameera-myproject-java17-0.1.0.bala"); + Path balaDestPath = balaDirPath.resolve("extracted"); + ProjectUtils.extractBala(balaFilePath, balaDestPath); + String packageJsonContent = Files.readString(balaDestPath.resolve("package.json")); + Assert.assertFalse(packageJsonContent.contains("\"graalvmCompatible\"")); + } + + @Test(description = "Pack with graalvm compatible single dependency.") + public void testPackProjectWithPlatformLibsGraal1() throws IOException { + Path projectPath = this.testResources.resolve("validProjectWithPlatformLibsGraal1"); + System.setProperty(USER_DIR, projectPath.toString()); + + PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); + new CommandLine(packCommand).parseArgs(); + packCommand.execute(); + String buildLog = readOutput(true); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("pack-project-with-platform-libs-graal1.txt")); + Path balaDirPath = projectPath.resolve("target").resolve("bala"); + Path balaFilePath = balaDirPath.resolve("sameera-myproject-java17-0.1.0.bala"); + Path balaDestPath = balaDirPath.resolve("extracted"); + ProjectUtils.extractBala(balaFilePath, balaDestPath); + String packageJsonContent = Files.readString(balaDestPath.resolve("package.json")); + Assert.assertTrue(packageJsonContent.contains("\"graalvmCompatible\": true")); + } + + @Test(description = "Pack with non-graalvm compatible single dependency") + public void testPackProjectWithPlatformLibsGraal2() throws IOException { + Path projectPath = this.testResources.resolve("validProjectWithPlatformLibsGraal2"); + System.setProperty(USER_DIR, projectPath.toString()); + + PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); + new CommandLine(packCommand).parseArgs(); + packCommand.execute(); + String buildLog = readOutput(true); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("pack-project-with-platform-libs-graal2.txt")); + Path balaDirPath = projectPath.resolve("target").resolve("bala"); + Path balaFilePath = balaDirPath.resolve("sameera-myproject-java17-0.1.0.bala"); + Path balaDestPath = balaDirPath.resolve("extracted"); + ProjectUtils.extractBala(balaFilePath, balaDestPath); + String packageJsonContent = Files.readString(balaDestPath.resolve("package.json")); + Assert.assertTrue(packageJsonContent.contains("\"graalvmCompatible\": false")); + } + + @Test(description = "Pack with a non-graalvm compatible dependency, a graalvm compatible dependency, dependency " + + "with unspecified attribute") + public void testPackProjectWithPlatformLibsGraal3() throws IOException { + Path projectPath = this.testResources.resolve("validProjectWithPlatformLibsGraal3"); + System.setProperty(USER_DIR, projectPath.toString()); + + PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); + new CommandLine(packCommand).parseArgs(); + packCommand.execute(); + String buildLog = readOutput(true); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("pack-project-with-platform-libs-graal3.txt")); + Path balaDirPath = projectPath.resolve("target").resolve("bala"); + Path balaFilePath = balaDirPath.resolve("sameera-myproject-java17-0.1.0.bala"); + Path balaDestPath = balaDirPath.resolve("extracted"); + ProjectUtils.extractBala(balaFilePath, balaDestPath); + String packageJsonContent = Files.readString(balaDestPath.resolve("package.json")); + Assert.assertTrue(packageJsonContent.contains("\"graalvmCompatible\": false")); + } + + @Test(description = "Pack with a graalvm compatible dependency, dependency with unspecified attribute") + public void testPackProjectWithPlatformLibsGraal4() throws IOException { + Path projectPath = this.testResources.resolve("validProjectWithPlatformLibsGraal4"); + System.setProperty(USER_DIR, projectPath.toString()); + + PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); + new CommandLine(packCommand).parseArgs(); + packCommand.execute(); + String buildLog = readOutput(true); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("pack-project-with-platform-libs-graal4.txt")); + Path balaDirPath = projectPath.resolve("target").resolve("bala"); + Path balaFilePath = balaDirPath.resolve("sameera-myproject-java17-0.1.0.bala"); + Path balaDestPath = balaDirPath.resolve("extracted"); + ProjectUtils.extractBala(balaFilePath, balaDestPath); + String packageJsonContent = Files.readString(balaDestPath.resolve("package.json")); + Assert.assertFalse(packageJsonContent.contains("\"graalvmCompatible\"")); + } + + @Test(description = "Pack with a non-graalvm compatible dependency, 'graalvmCompatible=true' attribute set at " + + "the platform") + public void testPackProjectWithPlatformLibsGraal5() throws IOException { + Path projectPath = this.testResources.resolve("validProjectWithPlatformLibsGraal5"); + System.setProperty(USER_DIR, projectPath.toString()); PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); new CommandLine(packCommand).parseArgs(); packCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("pack-project-with-platform-libs.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("pack-project-with-platform-libs-graal5.txt")); + Path balaDirPath = projectPath.resolve("target").resolve("bala"); + Path balaFilePath = balaDirPath.resolve("sameera-myproject-java17-0.1.0.bala"); + Path balaDestPath = balaDirPath.resolve("extracted"); + ProjectUtils.extractBala(balaFilePath, balaDestPath); + String packageJsonContent = Files.readString(balaDestPath.resolve("package.json")); + Assert.assertTrue(packageJsonContent.contains("\"graalvmCompatible\": false")); + } + + @Test(description = "Pack with a graalvm compatible dependency, 'graalvmCompatible=false' attribute set at " + + "the platform") + public void testPackProjectWithPlatformLibsGraal6() throws IOException { + Path projectPath = this.testResources.resolve("validProjectWithPlatformLibsGraal6"); + System.setProperty(USER_DIR, projectPath.toString()); + + PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); + new CommandLine(packCommand).parseArgs(); + packCommand.execute(); + String buildLog = readOutput(true); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("pack-project-with-platform-libs-graal6.txt")); + Path balaDirPath = projectPath.resolve("target").resolve("bala"); + Path balaFilePath = balaDirPath.resolve("sameera-myproject-java17-0.1.0.bala"); + Path balaDestPath = balaDirPath.resolve("extracted"); + ProjectUtils.extractBala(balaFilePath, balaDestPath); + String packageJsonContent = Files.readString(balaDestPath.resolve("package.json")); + Assert.assertTrue(packageJsonContent.contains("\"graalvmCompatible\": false")); + } + + @Test(description = "Pack with a graalvm compatible dependency, dependency with unspecified attribute with " + + "different java platforms") + public void testPackProjectWithPlatformLibsGraal7() throws IOException { + Path projectPath = this.testResources.resolve("validProjectWithPlatformLibsGraal7"); + System.setProperty(USER_DIR, projectPath.toString()); + + PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); + new CommandLine(packCommand).parseArgs(); + packCommand.execute(); + String buildLog = readOutput(true); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("pack-project-with-platform-libs-graal7.txt")); + Path balaDirPath = projectPath.resolve("target").resolve("bala"); + Path balaFilePath = balaDirPath.resolve("sameera-myproject-java17-0.1.0.bala"); + Path balaDestPath = balaDirPath.resolve("extracted"); + ProjectUtils.extractBala(balaFilePath, balaDestPath); + String packageJsonContent = Files.readString(balaDestPath.resolve("package.json")); + Assert.assertTrue(packageJsonContent.contains("\"graalvmCompatible\": false")); } @AfterClass diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/PrintUtilsTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/PrintUtilsTest.java index 3e26a909cfde..6519bab7d161 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/PrintUtilsTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/PrintUtilsTest.java @@ -34,7 +34,6 @@ import java.io.PrintStream; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; /** @@ -46,8 +45,7 @@ public class PrintUtilsTest { private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); private static final PrintStream originalOut = System.out; private static final PrintStream errStream = System.err; - private static final Path PRINT_UTILS_OUTPUT_DIR = Paths - .get("src", "test", "resources", "test-resources", "print-utils-output"); + private static final Path PRINT_UTILS_OUTPUT_DIR = Path.of("src/test/resources/test-resources/print-utils-output"); @DataProvider(name = "searchResultsWithTerminalWidth") public Object[][] provideSearchResultsWithTerminalWidth() @@ -79,7 +77,7 @@ public void testPrintModules(List packages, String terminalWidth, Strin if (!(outContent.toString().contains(expectedOutput))) { errStream.println("expected output not contains in output stream"); errStream.println("expected output:\n" + expectedOutput); - errStream.println("print stream:" + outContent.toString()); + errStream.println("print stream:" + outContent); Assert.fail(); } } diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/ProfileCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/ProfileCommandTest.java index 69c2af8fc44d..496b8aee3e77 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/ProfileCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/ProfileCommandTest.java @@ -18,23 +18,34 @@ package io.ballerina.cli.cmd; +import io.ballerina.cli.launcher.BLauncherException; +import io.ballerina.projects.util.BuildToolUtils; import io.ballerina.projects.util.ProjectUtils; +import org.ballerinalang.test.BCompileUtil; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; +import org.wso2.ballerinalang.util.RepoUtils; import picocli.CommandLine; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.net.URI; import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; +import java.util.List; import java.util.Objects; import static io.ballerina.cli.cmd.CommandOutputUtils.getOutput; +import static io.ballerina.cli.cmd.CommandOutputUtils.replaceDependenciesTomlContent; +import static io.ballerina.projects.util.ProjectConstants.DIST_CACHE_DIRECTORY; +import static io.ballerina.projects.util.ProjectConstants.USER_DIR_PROPERTY; /** * Profile command tests. @@ -44,8 +55,8 @@ public class ProfileCommandTest extends BaseCommandTest { private Path testResources; - static Path logFile = Paths.get(".", "src", "test", "resources", "compiler_plugin_tests", - "log_creator_combined_plugin", "compiler-plugin.txt"); + private static final Path logFile = Path.of("build/logs/log_creator_combined_plugin/compiler-plugin.txt") + .toAbsolutePath(); @BeforeSuite public void setupSuite() throws IOException { @@ -53,6 +64,7 @@ public void setupSuite() throws IOException { Files.writeString(logFile, ""); } + @Override @BeforeClass public void setup() throws IOException { super.setup(); @@ -60,7 +72,7 @@ public void setup() throws IOException { this.testResources = super.tmpDir.resolve("build-test-resources"); URI testResourcesURI = Objects.requireNonNull( getClass().getClassLoader().getResource("test-resources")).toURI(); - Path resourceURI = Paths.get(testResourcesURI); + Path resourceURI = Path.of(testResourcesURI); Files.walkFileTree(resourceURI, new BuildCommandTest.Copy(resourceURI, this.testResources)); } catch (URISyntaxException e) { @@ -71,17 +83,17 @@ public void setup() throws IOException { @Test(description = "Profile a ballerina project") public void testRunBalProjectWithProfileFlag() throws IOException { - Path projectPath = this.testResources.resolve("projectForProfile").resolve("package_a"); - System.setProperty("user.dir", projectPath.toString()); + Path projectPath = this.testResources.resolve("projectForProfile/package_a"); + System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream(); - System.setOut(new java.io.PrintStream(out)); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + System.setOut(new PrintStream(out)); ProfileCommand profileCommand = new ProfileCommand(projectPath, printStream, false); profileCommand.execute(); - String buildLog = readOutput(true).replaceAll("\r", "").strip(); + String buildLog = readOutput(true).replaceAll("\r", "").replaceAll("\\\\", "/").strip(); Assert.assertEquals(buildLog, getOutput("run-project-with-profile.txt")); - Path htmlPath = projectPath.resolve("target").resolve("profiler").resolve("ProfilerReport.html"); + Path htmlPath = projectPath.resolve("target/profiler/ProfilerReport.html"); Assert.assertTrue(htmlPath.toFile().exists()); try { String htmlContent = Files.readString(htmlPath); @@ -95,17 +107,17 @@ public void testRunBalProjectWithProfileFlag() throws IOException { @Test(description = "Profile a ballerina project with build tools") public void testRunBalProjectWithProfileFlagWithBuildTools() throws IOException { - Path projectPath = this.testResources.resolve("projectForProfile").resolve("package_b"); - System.setProperty("user.dir", projectPath.toString()); + Path projectPath = this.testResources.resolve("projectForProfile/package_b"); + System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream(); - System.setOut(new java.io.PrintStream(out)); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + System.setOut(new PrintStream(out)); ProfileCommand profileCommand = new ProfileCommand(projectPath, printStream, false); profileCommand.execute(); - String buildLog = readOutput(true).replaceAll("\r", "").strip(); + String buildLog = readOutput(true).replaceAll("\r", "").replaceAll("\\\\", "/").strip(); Assert.assertEquals(buildLog, getOutput("profile-project-with-build-tool.txt")); - Path htmlPath = projectPath.resolve("target").resolve("profiler").resolve("ProfilerReport.html"); + Path htmlPath = projectPath.resolve("target/profiler/ProfilerReport.html"); Assert.assertTrue(htmlPath.toFile().exists()); try { String htmlContent = Files.readString(htmlPath); @@ -120,8 +132,8 @@ public void testRunBalProjectWithProfileFlagWithBuildTools() throws IOException @Test(description = "Test profile command with help") public void testProfileCommandAndHelp() throws IOException { String[] args = {"--help"}; - Path projectPath = this.testResources.resolve("projectForProfile").resolve("package_a"); - System.setProperty("user.dir", projectPath.toString()); + Path projectPath = this.testResources.resolve("projectForProfile/package_a"); + System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); ProfileCommand profileCommand = new ProfileCommand(projectPath, printStream, false); new CommandLine(profileCommand).parseArgs(args); profileCommand.execute(); @@ -129,6 +141,43 @@ public void testProfileCommandAndHelp() throws IOException { "generate flame graph")); } + @Test(description = "Profile an empty package") + public void testProfileEmptyProject() throws IOException { + Path projectPath = this.testResources.resolve("emptyPackage"); + System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); + + ProfileCommand profileCommand = new ProfileCommand(projectPath, printStream, false); + new CommandLine(profileCommand).parseArgs(); + try { + profileCommand.execute(); + } catch (BLauncherException e) { + List messages = e.getMessages(); + Assert.assertEquals(messages.size(), 1); + Assert.assertEquals(messages.get(0), getOutput("build-empty-package.txt")); + } + } + + @Test(description = "Profile an empty package with code generator build tools") + public void testProfileEmptyProjectWithBuildTools() throws IOException { + Path testDistCacheDirectory = Path.of("build").toAbsolutePath().resolve(DIST_CACHE_DIRECTORY); + BCompileUtil.compileAndCacheBala( + testResources.resolve("buildToolResources/tools/ballerina-generate-file").toString()); + Path projectPath = this.testResources.resolve("emptyProjectWithBuildTool"); + replaceDependenciesTomlContent(projectPath, "**INSERT_DISTRIBUTION_VERSION_HERE**", + RepoUtils.getBallerinaShortVersion()); + System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); + try (MockedStatic repoUtils = Mockito.mockStatic( + BuildToolUtils.class, Mockito.CALLS_REAL_METHODS)) { + repoUtils.when(BuildToolUtils::getCentralBalaDirPath).thenReturn(testDistCacheDirectory.resolve("bala")); + ProfileCommand profileCommand = new ProfileCommand(projectPath, printStream, false); + new CommandLine(profileCommand).parseArgs(); + profileCommand.execute(); + } + String buildLog = readOutput(true); + Assert.assertEquals(buildLog.replaceAll("\r", "").replace("\\", "/"), + getOutput("profile-empty-project-with-build-tools.txt")); + } + @AfterSuite public void cleanUp() throws IOException { Files.deleteIfExists(logFile); diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/ProjectWatcherTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/ProjectWatcherTest.java new file mode 100644 index 000000000000..842d86aa12a4 --- /dev/null +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/ProjectWatcherTest.java @@ -0,0 +1,351 @@ +package io.ballerina.cli.cmd; + +import io.ballerina.cli.utils.ProjectWatcher; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import picocli.CommandLine; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import static io.ballerina.cli.cmd.CommandOutputUtils.getOutput; + +/** + * Tests for the --watch flag in the run command. + * + * @since 2201.11.0 + */ +public class ProjectWatcherTest extends BaseCommandTest { + private static final String WATCH_FLAG = "--watch"; + private static final int THREAD_SLEEP_DURATION_IN_MS = 8000; + private static final String PROJECT_NAME_PLACEHOLDER = "INSERT_PROJECT_NAME"; + + private Path watchTestResources; + private Thread watcherThread; + private AtomicReference watcher; + + @Override + @BeforeClass + public void setup() throws IOException { + super.setup(); + try { + Path testResources = super.tmpDir.resolve("build-test-resources"); + this.watchTestResources = testResources.resolve("watchFlagResources"); + URI testResourcesURI = Objects.requireNonNull( + getClass().getClassLoader().getResource("test-resources")).toURI(); + Files.walkFileTree(Path.of(testResourcesURI), + new BuildCommandTest.Copy(Path.of(testResourcesURI), testResources)); + watcher = new AtomicReference<>(); + } catch (URISyntaxException e) { + Assert.fail("error loading resources"); + } + } + + @Test(description = "Run a correct bal service file and do a correct change") + public void testRunWatchCorrectBalFileWithCorrectChange() throws IOException, InterruptedException { + Path balFilePath = createTempFileFromTestResource("service.bal"); + RunCommand runCommand = new RunCommand(balFilePath, printStream, false); + new CommandLine(runCommand).parseArgs(WATCH_FLAG, balFilePath.toString()); + CountDownLatch latch = new CountDownLatch(1); + watcherThread = new Thread(() -> { + try { + watcher.set(new ProjectWatcher(runCommand, balFilePath, printStream)); + latch.countDown(); + watcher.get().watch(); + } catch (IOException e) { + Assert.fail("Error occurred while watching the project: " + e); + } + }); + watcherThread.start(); + latch.await(); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + replaceFileContent(balFilePath, this.watchTestResources.resolve("service-updated.bal")); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + String actualOutput = readOutput(true).replace("\r", ""); + String expectedOutput = readExpectedOutputFile("watch-correct-service-file-correct-change.txt", balFilePath); + Assert.assertEquals(actualOutput, expectedOutput); + } + + @Test(description = "Run a correct bal service file and do a erroneous change") + public void testRunWatchCorrectBalFileWithErroneousChange() throws IOException, InterruptedException { + Path balFilePath = createTempFileFromTestResource("service.bal"); + RunCommand runCommand = new RunCommand(balFilePath, printStream, false); + new CommandLine(runCommand).parseArgs(WATCH_FLAG, balFilePath.toString()); + CountDownLatch latch = new CountDownLatch(1); + watcherThread = new Thread(() -> { + try { + watcher.set(new ProjectWatcher(runCommand, balFilePath, printStream)); + latch.countDown(); + watcher.get().watch(); + } catch (IOException e) { + Assert.fail("Error occurred while watching the project: " + e); + } + }); + watcherThread.start(); + latch.await(); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + replaceFileContent(balFilePath, this.watchTestResources.resolve("service-error.bal")); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + String actualOutput = readOutput(true).replace("\r", ""); + String expectedOutput = readExpectedOutputFile("watch-correct-service-file-error-change.txt", balFilePath); + Assert.assertEquals(actualOutput, expectedOutput); + } + + @Test(description = "Run a erroneous bal service file and do a correct change") + public void testRunWatchErroneousBalFileWithCorrectChange() throws IOException, InterruptedException { + Path balFilePath = createTempFileFromTestResource("service-error.bal"); + RunCommand runCommand = new RunCommand(balFilePath, printStream, false); + new CommandLine(runCommand).parseArgs(WATCH_FLAG, balFilePath.toString()); + CountDownLatch latch = new CountDownLatch(1); + watcherThread = new Thread(() -> { + try { + watcher.set(new ProjectWatcher(runCommand, balFilePath, printStream)); + latch.countDown(); + watcher.get().watch(); + } catch (IOException e) { + Assert.fail("Error occurred while watching the project: " + e); + } + }); + watcherThread.start(); + latch.await(); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + replaceFileContent(balFilePath, this.watchTestResources.resolve("service.bal")); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + String actualOutput = readOutput(true).replace("\r", ""); + String expectedOutput = readExpectedOutputFile("watch-error-service-file-correct-change.txt", balFilePath); + Assert.assertEquals(actualOutput, expectedOutput); + } + + @Test(description = "Run a bal file with no service") + public void testRunWatchBalFileWithNoService() throws IOException, InterruptedException { + Path balFilePath = createTempFileFromTestResource("main.bal"); + RunCommand runCommand = new RunCommand(balFilePath, printStream, false); + new CommandLine(runCommand).parseArgs(WATCH_FLAG, balFilePath.toString()); + CountDownLatch latch = new CountDownLatch(1); + watcherThread = new Thread(() -> { + try { + watcher.set(new ProjectWatcher(runCommand, balFilePath, printStream)); + latch.countDown(); + watcher.get().watch(); + } catch (IOException e) { + Assert.fail("Error occurred while watching the project: " + e); + } + }); + watcherThread.start(); + latch.await(); + watcherThread.join(THREAD_SLEEP_DURATION_IN_MS); + Assert.assertFalse(watcherThread.isAlive()); + String actualOutput = readOutput(true).replace("\r", ""); + String expectedOutput = readExpectedOutputFile("watch-no-service-file.txt", balFilePath); + Assert.assertEquals(actualOutput, expectedOutput); + } + + @Test(description = "Run a bal service project and do a correct change") + public void testRunWatchBalProjectWithCorrectChange() throws IOException, InterruptedException { + Path balProjectPath = createTempDirFromTestResource("service"); + RunCommand runCommand = new RunCommand(balProjectPath, printStream, false); + new CommandLine(runCommand).parseArgs(WATCH_FLAG, balProjectPath.toString()); + CountDownLatch latch = new CountDownLatch(1); + watcherThread = new Thread(() -> { + try { + watcher.set(new ProjectWatcher(runCommand, balProjectPath, printStream)); + latch.countDown(); + watcher.get().watch(); + } catch (IOException e) { + Assert.fail("Error occurred while watching the project: " + e); + } + }); + watcherThread.start(); + latch.await(); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + + // Update a source file + replaceFileContent(balProjectPath.resolve("service.bal"), + this.watchTestResources.resolve("project-service-updated.bal")); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + + // Add a new source file + Files.copy(this.watchTestResources.resolve("constants.bal"), balProjectPath.resolve("constants.bal")); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + + // Remove a source file + Files.delete(balProjectPath.resolve("constants.bal")); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + String actualOutput = readOutput(true).replace("\r", ""); + String expectedOutput = readExpectedOutputFile("watch-correct-service-project-correct-change.txt", + balProjectPath); + Assert.assertEquals(actualOutput, expectedOutput); + } + + @Test(description = "Run a bal project with no service") + public void testRunWatchBalProjectWithNoService() throws IOException, InterruptedException { + Path balProjectPath = createTempDirFromTestResource("main"); + RunCommand runCommand = new RunCommand(balProjectPath, printStream, false); + new CommandLine(runCommand).parseArgs(WATCH_FLAG, balProjectPath.toString()); + CountDownLatch latch = new CountDownLatch(1); + watcherThread = new Thread(() -> { + try { + watcher.set(new ProjectWatcher(runCommand, balProjectPath, printStream)); + latch.countDown(); + watcher.get().watch(); + } catch (IOException e) { + Assert.fail("Error occurred while watching the project: " + e); + } + }); + watcherThread.start(); + latch.await(); + watcherThread.join(THREAD_SLEEP_DURATION_IN_MS); + Assert.assertFalse(watcherThread.isAlive()); + String actualOutput = readOutput(true).replace("\r", ""); + String expectedOutput = readExpectedOutputFile("watch-no-service-project.txt", balProjectPath); + Assert.assertEquals(actualOutput, expectedOutput); + } + + @Test(description = "Run a bal service project and do valid file change") + public void testRunWatchBalProjectWithValidFileChanges() throws IOException, InterruptedException { + Path balProjectPath = createTempDirFromTestResource("service"); + RunCommand runCommand = new RunCommand(balProjectPath, printStream, false); + new CommandLine(runCommand).parseArgs(WATCH_FLAG, balProjectPath.toString()); + CountDownLatch latch = new CountDownLatch(1); + watcherThread = new Thread(() -> { + try { + watcher.set(new ProjectWatcher(runCommand, balProjectPath, printStream)); + latch.countDown(); + watcher.get().watch(); + } catch (IOException e) { + Assert.fail("Error occurred while watching the project: " + e); + } + }); + watcherThread.start(); + latch.await(); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + + // Update the Ballerina.toml + replaceFileContent(balProjectPath.resolve("Ballerina.toml"), + this.watchTestResources.resolve("Ballerina-copy.toml")); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + + // Add a new module with a source file + Files.copy(this.watchTestResources.resolve("mod1.bal"), + balProjectPath.resolve("modules").resolve("mod1").resolve("mod1.bal")); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + + // Add a new resource file + Files.copy(this.watchTestResources.resolve("hello.txt"), + balProjectPath.resolve("resources").resolve("hello.txt")); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + + String actualOutput = readOutput(true).replace("\r", ""); + String expectedOutput = readExpectedOutputFile("watch-service-project-valid-changes.txt", balProjectPath); + Assert.assertEquals(actualOutput, expectedOutput); + } + + @Test(description = "Run a bal service project and do invalid file change") + public void testRunWatchBalProjectWithInvalidFileChanges() throws IOException, InterruptedException { + Path balProjectPath = createTempDirFromTestResource("service"); + RunCommand runCommand = new RunCommand(balProjectPath, printStream, false); + new CommandLine(runCommand).parseArgs(WATCH_FLAG, balProjectPath.toString()); + CountDownLatch latch = new CountDownLatch(1); + watcherThread = new Thread(() -> { + try { + watcher.set(new ProjectWatcher(runCommand, balProjectPath, printStream)); + latch.countDown(); + watcher.get().watch(); + } catch (IOException e) { + Assert.fail("Error occurred while watching the project: " + e); + } + }); + watcherThread.start(); + latch.await(); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + + // Add test file + Path testFilePath = balProjectPath.resolve("tests").resolve("test.bal"); + Files.copy(this.watchTestResources.resolve("constants.bal"), testFilePath); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + + // Change test file + replaceFileContent(testFilePath, this.watchTestResources.resolve("project-service-updated.bal")); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + + // Delete a test file + Files.delete(testFilePath); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + + // Add a test file to a module + Files.copy(this.watchTestResources.resolve("constants.bal"), + balProjectPath.resolve("modules").resolve("mod1").resolve("tests").resolve("test.bal")); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + + // Add a source file into modules/ + Files.copy(this.watchTestResources.resolve("constants.bal"), + balProjectPath.resolve("modules").resolve("constants.bal")); + + // Add a json file to the root + Files.copy(this.watchTestResources.resolve("hello.json"), balProjectPath.resolve("hello.json")); + + // Add a source file to target/ + Files.copy(this.watchTestResources.resolve("constants.bal"), + balProjectPath.resolve("target").resolve("constants.bal")); + Thread.sleep(THREAD_SLEEP_DURATION_IN_MS); + + String actualOutput = readOutput(true).replace("\r", ""); + String expectedOutput = readExpectedOutputFile("watch-service-project-invalid-changes.txt", balProjectPath); + Assert.assertEquals(actualOutput, expectedOutput); + } + + @Override + @AfterMethod + public void afterMethod() { + try { + if (watcherThread != null && watcher.get() != null) { + stopProjectWatcher(watcherThread, watcher.get()); + } + } catch (InterruptedException e) { + Assert.fail("Error occurred while stopping the project watcher. " + + "Please kill any stale java processes that were started by the project watcher tests: " + e); + } + } + + private Path createTempFileFromTestResource(String fileName) throws IOException { + Path balFilePath = this.watchTestResources.resolve(fileName); + Path tempFilePath = Files.createTempFile("service", ".bal"); + replaceFileContent(tempFilePath, balFilePath); + return tempFilePath; + } + + private Path createTempDirFromTestResource(String projectName) throws IOException { + Path balProjectPath = this.watchTestResources.resolve(projectName); + Path tempProjectPath = Files.createTempDirectory("service"); + tempProjectPath.toFile().deleteOnExit(); + Files.walkFileTree(balProjectPath, new BuildCommandTest.Copy(balProjectPath, tempProjectPath)); + return tempProjectPath; + } + + private void replaceFileContent(Path filePath, Path copyFrom) { + try { + String newContent = Files.readString(copyFrom); + Files.writeString(filePath, newContent); + } catch (IOException e) { + Assert.fail("Error occurred while writing to the file: " + e); + } + } + + private String readExpectedOutputFile(String expectedOutputFile, Path balFilePath) throws IOException { + return getOutput(expectedOutputFile) + .replace(PROJECT_NAME_PLACEHOLDER, balFilePath.getFileName().toString()); + } + + private void stopProjectWatcher(Thread thread, ProjectWatcher watcher) throws InterruptedException { + watcher.stopWatching(); + thread.join(); + } +} diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/PullCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/PullCommandTest.java index 5e00924e4438..dd9e5dccfe8f 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/PullCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/PullCommandTest.java @@ -21,7 +21,6 @@ import io.ballerina.projects.Settings; import io.ballerina.projects.TomlDocument; import io.ballerina.projects.internal.SettingsBuilder; -import org.ballerinalang.toml.exceptions.SettingsTomlException; import org.mockito.MockedStatic; import org.mockito.Mockito; import org.testng.Assert; @@ -32,7 +31,6 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; /** * Pull command tests. @@ -46,11 +44,11 @@ public class PullCommandTest extends BaseCommandTest { @Test(description = "Pull package without package name") public void testPullWithoutPackage() throws IOException { PullCommand pullCommand = new PullCommand(printStream, false); - new CommandLine(pullCommand).parse(); + new CommandLine(pullCommand).parseArgs(); pullCommand.execute(); String buildLog = readOutput(true); - String actual = buildLog.replaceAll("\r", ""); + String actual = buildLog.replace("\r", ""); Assert.assertTrue(actual.contains("ballerina: no package given")); Assert.assertTrue(actual.contains("bal pull ")); } @@ -58,11 +56,11 @@ public void testPullWithoutPackage() throws IOException { @Test(description = "Pull package with too many args") public void testPullWithTooManyArgs() throws IOException { PullCommand pullCommand = new PullCommand(printStream, false); - new CommandLine(pullCommand).parse(TEST_PKG_NAME, "tests"); + new CommandLine(pullCommand).parseArgs(TEST_PKG_NAME, "tests"); pullCommand.execute(); String buildLog = readOutput(true); - String actual = buildLog.replaceAll("\r", ""); + String actual = buildLog.replace("\r", ""); Assert.assertTrue(actual.contains("ballerina: too many arguments")); Assert.assertTrue(actual.contains("bal pull ")); } @@ -70,13 +68,13 @@ public void testPullWithTooManyArgs() throws IOException { @Test(description = "Pull package with invalid package name") public void testPullInvalidPackage() throws IOException { PullCommand pullCommand = new PullCommand(printStream, false); - new CommandLine(pullCommand).parse("wso2/winery/1.0.0"); + new CommandLine(pullCommand).parseArgs("wso2/winery/1.0.0"); pullCommand.execute(); String buildLog = readOutput(true); String actual = buildLog.replaceAll("\r", ""); Assert.assertTrue( - actual.contains("ballerina: invalid package name. Provide the package name with the organization.")); + actual.contains("ballerina: invalid package. Provide the package name with the organization.")); Assert.assertTrue( actual.contains("bal pull {/ | /:}")); } @@ -84,7 +82,7 @@ public void testPullInvalidPackage() throws IOException { @Test(description = "Pull package with invalid org") public void testPullPackageWithInvalidOrg() throws IOException { PullCommand pullCommand = new PullCommand(printStream, false); - new CommandLine(pullCommand).parse("wso2-dev/winery"); + new CommandLine(pullCommand).parseArgs("wso2-dev/winery"); pullCommand.execute(); String buildLog = readOutput(true); @@ -98,7 +96,7 @@ public void testPullPackageWithInvalidOrg() throws IOException { @Test(description = "Pull package with invalid name") public void testPullPackageWithInvalidName() throws IOException { PullCommand pullCommand = new PullCommand(printStream, false); - new CommandLine(pullCommand).parse("wso2/winery$:1.0.0"); + new CommandLine(pullCommand).parseArgs("wso2/winery$:1.0.0"); pullCommand.execute(); String buildLog = readOutput(true); @@ -112,7 +110,7 @@ public void testPullPackageWithInvalidName() throws IOException { @Test(description = "Pull package with invalid version") public void testPullPackageWithInvalidVersion() throws IOException { PullCommand pullCommand = new PullCommand(printStream, false); - new CommandLine(pullCommand).parse("wso2/winery:1.0.0.0"); + new CommandLine(pullCommand).parseArgs("wso2/winery:1.0.0.0"); pullCommand.execute(); String buildLog = readOutput(true); @@ -129,7 +127,7 @@ public void testPullCommandArgAndHelp() throws IOException { // Test if no arguments was passed in String[] args = { "sample2", "--help" }; PullCommand pullCommand = new PullCommand(printStream, false); - new CommandLine(pullCommand).parse(args); + new CommandLine(pullCommand).parseArgs(args); pullCommand.execute(); Assert.assertTrue(readOutput().contains("ballerina-pull - Fetch packages from Ballerina Central")); @@ -140,23 +138,21 @@ public void testPullCommandWithHelp() throws IOException { // Test if no arguments was passed in String[] args = { "-h" }; PullCommand pullCommand = new PullCommand(printStream, false); - new CommandLine(pullCommand).parse(args); + new CommandLine(pullCommand).parseArgs(args); pullCommand.execute(); Assert.assertTrue(readOutput().contains("ballerina-pull - Fetch packages from Ballerina Central")); } @Test(description = "Pull a package from custom remote repository") - public void testPullCustom() throws SettingsTomlException, IOException { + public void testPullCustom() { - Path customrRepoPath = Paths.get("src", "test", "resources", "test-resources", "custom-repo", - "repositories", "repo-push-pull"); - Path settingsTomlPath = Paths.get("src", "test", "resources", "test-resources", "custom-repo", - "Settings.toml"); - Path mockBallerinaHome = Paths.get("build").resolve("ballerina-home"); + Path customrRepoPath = Path.of("src/test/resources/test-resources/custom-repo/repositories/repo-push-pull"); + Path settingsTomlPath = Path.of("src/test/resources/test-resources/custom-repo/Settings.toml"); + Path mockBallerinaHome = Path.of("build/ballerina-home"); PullCommand pullCommand = new PullCommand(printStream, false); - new CommandLine(pullCommand).parse("luheerathan/pact1:0.1.0", "--repository=repo-push-pull"); + new CommandLine(pullCommand).parseArgs("luheerathan/pact1:0.1.0", "--repository=repo-push-pull"); try (MockedStatic repoUtils = Mockito.mockStatic(RepoUtils.class, Mockito.CALLS_REAL_METHODS)) { repoUtils.when(RepoUtils::createAndGetHomeReposPath).thenReturn(mockBallerinaHome); repoUtils.when(RepoUtils::readSettings).thenReturn(readMockSettings(settingsTomlPath, @@ -169,16 +165,14 @@ public void testPullCustom() throws SettingsTomlException, IOException { } @Test(description = "Pull a package from custom remote repository(not exist in Settings.toml)") - public void testPullNonExistingCustom() throws SettingsTomlException, IOException { + public void testPullNonExistingCustom() throws IOException { - Path customrRepoPath = Paths.get("src", "test", "resources", "test-resources", "custom-repo", - "repositories", "repo-push-pull"); - Path settingsTomlPath = Paths.get("src", "test", "resources", "test-resources", "custom-repo", - "Settings.toml"); - Path mockBallerinaHome = Paths.get("build").resolve("ballerina-home"); + Path customrRepoPath = Path.of("src/test/resources/test-resources/custom-repo/repositories/repo-push-pull"); + Path settingsTomlPath = Path.of("src/test/resources/test-resources/custom-repo/Settings.toml"); + Path mockBallerinaHome = Path.of("build/ballerina-home"); PullCommand pullCommand = new PullCommand(printStream, false); - new CommandLine(pullCommand).parse("luheerathan/pact1:0.1.0", "--repository=repo-push-pul"); + new CommandLine(pullCommand).parseArgs("luheerathan/pact1:0.1.0", "--repository=repo-push-pul"); try (MockedStatic repoUtils = Mockito.mockStatic(RepoUtils.class, Mockito.CALLS_REAL_METHODS)) { repoUtils.when(RepoUtils::createAndGetHomeReposPath).thenReturn(mockBallerinaHome); repoUtils.when(RepoUtils::readSettings).thenReturn(readMockSettings(settingsTomlPath, @@ -191,7 +185,7 @@ public void testPullNonExistingCustom() throws SettingsTomlException, IOExceptio "Only repositories mentioned in the Settings.toml are supported.\n")); } - private static Settings readMockSettings(Path settingsFilePath, String repoPath) throws SettingsTomlException { + private static Settings readMockSettings(Path settingsFilePath, String repoPath) { try { String settingString = Files.readString(settingsFilePath); settingString = settingString.replaceAll("REPO_PATH", repoPath); diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/PushCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/PushCommandTest.java index ed0c74200b32..3c2046740d2a 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/PushCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/PushCommandTest.java @@ -26,11 +26,12 @@ import io.ballerina.projects.internal.ProjectFiles; import io.ballerina.projects.internal.SettingsBuilder; import io.ballerina.projects.util.ProjectConstants; +import io.ballerina.projects.util.ProjectUtils; import org.apache.commons.io.FileUtils; -import org.ballerinalang.toml.exceptions.SettingsTomlException; import org.mockito.MockedStatic; import org.mockito.Mockito; import org.testng.Assert; +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import org.wso2.ballerinalang.util.RepoUtils; @@ -43,7 +44,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Objects; import static io.ballerina.cli.cmd.CommandOutputUtils.getOutput; @@ -61,6 +61,7 @@ public class PushCommandTest extends BaseCommandTest { private static final String POM_EXTENSION = ".pom"; private Path testResources; + @Override @BeforeClass public void setup() throws IOException { super.setup(); @@ -68,41 +69,50 @@ public void setup() throws IOException { this.testResources = super.tmpDir.resolve("build-test-resources"); URI testResourcesURI = Objects.requireNonNull(getClass().getClassLoader().getResource("test-resources")) .toURI(); - Files.walkFileTree(Paths.get(testResourcesURI), - new BuildCommandTest.Copy(Paths.get(testResourcesURI), this.testResources)); + Files.walkFileTree(Path.of(testResourcesURI), + new BuildCommandTest.Copy(Path.of(testResourcesURI), this.testResources)); } catch (URISyntaxException e) { Assert.fail("error loading resources"); } } + @AfterMethod(alwaysRun = true) + @Override + public void afterMethod() throws IOException { + super.afterMethod(); + Path validBalProject = Path.of("build/validProjectWithTarget"); + ProjectUtils.deleteDirectory(validBalProject); + validBalProject = Path.of("build/tool-gayals"); + ProjectUtils.deleteDirectory(validBalProject); + } + @Test(description = "Push package with invalid path") public void testPushWithInvalidPath() throws IOException { Path validBalProject = this.testResources.resolve(VALID_PROJECT); PushCommand pushCommand = new PushCommand(validBalProject, printStream, printStream, false); String invalidPath = "tests"; - new CommandLine(pushCommand).parse(invalidPath); + new CommandLine(pushCommand).parseArgs(invalidPath); pushCommand.execute(); String buildLog = readOutput(true); - String actual = buildLog.replaceAll("\r", ""); + String actual = buildLog.replace("\r", ""); String expected = "path provided for the bala file does not exist: " + invalidPath + "."; Assert.assertTrue(actual.contains(expected)); } @Test (description = "Push a package to a custom remote repository") - public void testPushPackageCustom() throws IOException, SettingsTomlException { + public void testPushPackageCustom() throws IOException { String org = "luheerathan"; String packageName = "pact1"; String version = "0.1.0"; String expected = "Successfully pushed src/test/resources/test-resources/custom-repo/" + "luheerathan-pact1-any-0.1.0.bala to 'repo-push-pull' repository.\n"; - Path mockRepo = Paths.get("build").resolve("ballerina-home").resolve("repositories").resolve("repo-push-pull"); - Path balaPath = Paths.get("src", "test", "resources", "test-resources", "custom-repo", - "luheerathan-pact1-any-0.1.0.bala"); + Path mockRepo = Path.of("build/ballerina-home/repositories/repo-push-pull"); + Path balaPath = Path.of("src/test/resources/test-resources/custom-repo/luheerathan-pact1-any-0.1.0.bala"); PushCommand pushCommand = new PushCommand(null, printStream, printStream, false, balaPath); String[] args = { "--repository=repo-push-pull" }; - new CommandLine(pushCommand).parse(args); + new CommandLine(pushCommand).parseArgs(args); try (MockedStatic repoUtils = Mockito.mockStatic(RepoUtils.class, Mockito.CALLS_REAL_METHODS)) { repoUtils.when(RepoUtils::readSettings).thenReturn(readSettings(testResources.resolve("custom-repo") .resolve("Settings.toml"), mockRepo.toAbsolutePath().toString() @@ -110,31 +120,31 @@ public void testPushPackageCustom() throws IOException, SettingsTomlException { pushCommand.execute(); } String buildLog = readOutput(true); - String actual = buildLog.replaceAll("\r", ""); + String actual = buildLog.replace("\r", ""); Assert.assertEquals(actual.replace("\\", "/"), expected); String artifact = packageName + "-" + version + BALA_EXTENSION; String pomFile = packageName + "-" + version + POM_EXTENSION; String pushPullPath = mockRepo.resolve(org).resolve(packageName).resolve(version).toAbsolutePath().toString(); for (String ext : new String[]{".sha1", ".md5", ""}) { - Assert.assertTrue(Paths.get(pushPullPath, artifact + ext).toFile().exists()); - Assert.assertTrue(Paths.get(pushPullPath, pomFile + ext).toFile().exists()); + Assert.assertTrue(Path.of(pushPullPath, artifact + ext).toFile().exists()); + Assert.assertTrue(Path.of(pushPullPath, pomFile + ext).toFile().exists()); } } @Test (description = "Push a package to a custom remote repository(not exist in Settings.toml)") - public void testPushPackageNonExistingCustom() throws IOException, SettingsTomlException { + public void testPushPackageNonExistingCustom() throws IOException { String expected = "ballerina: unsupported repository 'repo-push-pul' found. " + "Only 'local' repository and repositories mentioned in the Settings.toml are supported.\n"; - Path mockRepo = Paths.get("build").resolve("ballerina-home").resolve("repositories").resolve("repo-push-pull"); - Path balaPath = Paths.get("src", "test", "resources", "test-resources", "custom-repo", - "luheerathan-pact1-any-0.1.0.bala"); + Path mockRepo = Path.of("build/ballerina-home/repositories/repo-push-pull"); + Path balaPath = Path.of("src/test/resources/test-resources/custom-repo/luheerathan-pact1-any-0.1.0.bala"); PushCommand pushCommand = new PushCommand(null, printStream, printStream, false, balaPath); String[] args = { "--repository=repo-push-pul" }; - new CommandLine(pushCommand).parse(args); + new CommandLine(pushCommand).parseArgs(args); try (MockedStatic repoUtils = Mockito.mockStatic(RepoUtils.class, Mockito.CALLS_REAL_METHODS)) { - repoUtils.when(RepoUtils::readSettings).thenReturn(readSettings(testResources.resolve("custom-repo") - .resolve("Settings.toml"), mockRepo.toAbsolutePath().toString())); + repoUtils.when(RepoUtils::readSettings).thenReturn( + readSettings(testResources.resolve("custom-repo/Settings.toml"), + mockRepo.toAbsolutePath().toString())); pushCommand.execute(); } String buildLog = readOutput(true); @@ -142,7 +152,7 @@ public void testPushPackageNonExistingCustom() throws IOException, SettingsTomlE Assert.assertEquals(actual, expected); } - private static Settings readSettings(Path settingsFilePath, String repoPath) throws SettingsTomlException { + private static Settings readSettings(Path settingsFilePath, String repoPath) { try { String settingString = Files.readString(settingsFilePath); settingString = settingString.replaceAll("REPO_PATH", repoPath); @@ -160,9 +170,8 @@ private static Settings readSettings(Path settingsFilePath, String repoPath) thr public void testPushWithInvalidFileExtension() throws IOException { Path validBalProject = this.testResources.resolve(VALID_PROJECT); PushCommand pushCommand = new PushCommand(validBalProject, printStream, printStream, false); - String invalidExtensionFilePath = this.testResources.resolve("non-bal-file") - .resolve("hello_world.txt").toString(); - new CommandLine(pushCommand).parse(invalidExtensionFilePath); + String invalidExtensionFilePath = this.testResources.resolve("non-bal-file/hello_world.txt").toString(); + new CommandLine(pushCommand).parseArgs(invalidExtensionFilePath); pushCommand.execute(); String buildLog = readOutput(true); @@ -173,21 +182,20 @@ public void testPushWithInvalidFileExtension() throws IOException { @Test(description = "Push package with custom path") public void testPushWithCustomPath() throws IOException { - Path validBalProject = Paths.get("build").resolve("validProjectWithTarget"); + Path validBalProject = Path.of("build/validProjectWithTarget"); FileUtils.copyDirectory( this.testResources.resolve("validProjectWithTarget").toFile(), validBalProject.toFile()); FileUtils.moveDirectory( validBalProject.resolve("target-dir").toFile(), validBalProject.resolve("custom").toFile()); - Path customTargetDirBalaPath = validBalProject.resolve("custom").resolve("bala") - .resolve("foo-winery-any-0.1.0.bala"); + Path customTargetDirBalaPath = validBalProject.resolve("custom/bala/foo-winery-any-0.1.0.bala"); PushCommand pushCommand = new PushCommand(validBalProject, printStream, printStream, false, customTargetDirBalaPath); String[] args = { "--repository=local" }; - new CommandLine(pushCommand).parse(args); + new CommandLine(pushCommand).parseArgs(args); - Path mockRepo = Paths.get("build").resolve("ballerina-home"); + Path mockRepo = Path.of("build/ballerina-home"); try (MockedStatic repoUtils = Mockito.mockStatic(RepoUtils.class)) { repoUtils.when(RepoUtils::createAndGetHomeReposPath).thenReturn(mockRepo); @@ -198,12 +206,11 @@ public void testPushWithCustomPath() throws IOException { String buildLog = readOutput(true); String actual = buildLog.replaceAll("\r", ""); - String expected = "Successfully pushed " + customTargetDirBalaPath.toString() + " to 'local' repository."; + String expected = "Successfully pushed " + customTargetDirBalaPath + " to 'local' repository."; Assert.assertTrue(actual.contains(expected)); try { - ProjectFiles.validateBalaProjectPath(mockRepo.resolve("repositories").resolve("local").resolve("bala") - .resolve("foo").resolve("winery").resolve("0.1.0").resolve("any")); + ProjectFiles.validateBalaProjectPath(mockRepo.resolve("repositories/local/bala/foo/winery/0.1.0/any")); } catch (ProjectException e) { Assert.fail(e.getMessage()); } @@ -211,21 +218,21 @@ public void testPushWithCustomPath() throws IOException { @Test(description = "Push a tool to local repository") public void testPushToolToLocal() throws IOException { - Path validBalProject = Paths.get("build").resolve("tool-gayals"); + Path validBalProject = Path.of("build/tool-gayals"); FileUtils.copyDirectory( this.testResources.resolve("tool-gayals").toFile(), validBalProject.toFile()); FileUtils.moveDirectory( validBalProject.resolve("target-dir").toFile(), validBalProject.resolve("custom").toFile()); - Path customTargetDirBalaPath = validBalProject.resolve("custom").resolve("bala") - .resolve("gayaldassanayake-tool_gayal-java17-1.1.0.bala"); + Path customTargetDirBalaPath = + validBalProject.resolve("custom/bala/gayaldassanayake-tool_gayal-java17-1.1.0.bala"); PushCommand pushCommand = new PushCommand(validBalProject, printStream, printStream, false, customTargetDirBalaPath); String[] args = { "--repository=local" }; - new CommandLine(pushCommand).parse(args); + new CommandLine(pushCommand).parseArgs(args); - Path mockRepo = Paths.get("build").resolve("ballerina-home"); + Path mockRepo = Path.of("build/ballerina-home"); try (MockedStatic repoUtils = Mockito.mockStatic(RepoUtils.class)) { repoUtils.when(RepoUtils::createAndGetHomeReposPath).thenReturn(mockRepo); @@ -236,19 +243,17 @@ public void testPushToolToLocal() throws IOException { String buildLog = readOutput(true); String actual = buildLog.replaceAll("\r", ""); - String expected = "Successfully pushed " + customTargetDirBalaPath.toString() + " to 'local' repository."; + String expected = "Successfully pushed " + customTargetDirBalaPath + " to 'local' repository."; Assert.assertTrue(actual.contains(expected)); try { - ProjectFiles.validateBalaProjectPath(mockRepo.resolve("repositories").resolve("local") - .resolve("bala").resolve("gayaldassanayake").resolve("tool_gayal") - .resolve("1.1.0").resolve("java17")); + ProjectFiles.validateBalaProjectPath( + mockRepo.resolve("repositories/local/bala/gayaldassanayake/tool_gayal/1.1.0/java17")); } catch (ProjectException e) { Assert.fail(e.getMessage()); } - Path localToolJsonPath = mockRepo.resolve("repositories").resolve("local").resolve("bala") - .resolve("local-tools.json"); + Path localToolJsonPath = mockRepo.resolve("repositories/local/bala/local-tools.json"); Assert.assertTrue(Files.exists(localToolJsonPath)); @@ -269,7 +274,7 @@ public void testPushWithoutBalaDir() throws IOException { Path validBalProject = this.testResources.resolve(VALID_PROJECT); PushCommand pushCommand = new PushCommand(validBalProject, printStream, printStream, false); - new CommandLine(pushCommand).parse(); + new CommandLine(pushCommand).parseArgs(); pushCommand.execute(); String buildLog = readOutput(true); @@ -284,22 +289,20 @@ public void testPushWithoutBala() throws IOException { // Build project PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); - new CommandLine(packCommand).parse(); + new CommandLine(packCommand).parseArgs(); packCommand.execute(); String buildLog = readOutput(true); Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("compile-bal-project.txt")); - Assert.assertTrue( - projectPath.resolve("target").resolve("bala").resolve("foo-winery-any-0.1.0.bala").toFile().exists()); + Assert.assertTrue(projectPath.resolve("target/bala/foo-winery-any-0.1.0.bala").toFile().exists()); // Delete bala - Assert.assertTrue( - projectPath.resolve("target").resolve("bala").resolve("foo-winery-any-0.1.0.bala").toFile().delete()); + Assert.assertTrue(projectPath.resolve("target/bala/foo-winery-any-0.1.0.bala").toFile().delete()); // Push String expected = "cannot find bala file for the package: winery. Run " + "'bal pack' to compile and generate the bala."; PushCommand pushCommand = new PushCommand(projectPath, printStream, printStream, false); - new CommandLine(pushCommand).parse(); + new CommandLine(pushCommand).parseArgs(); pushCommand.execute(); buildLog = readOutput(true); @@ -313,7 +316,7 @@ public void testPushCommandArgAndHelp() throws IOException { // Test if no arguments was passed in String[] args = { "sample2", "--help" }; PushCommand pushCommand = new PushCommand(validBalProject, printStream, printStream, false); - new CommandLine(pushCommand).parse(args); + new CommandLine(pushCommand).parseArgs(args); pushCommand.execute(); Assert.assertTrue(readOutput().contains("ballerina-push - Push the Ballerina Archive (BALA)")); @@ -325,7 +328,7 @@ public void testPushCommandWithHelp() throws IOException { // Test if no arguments was passed in String[] args = { "-h" }; PushCommand pushCommand = new PushCommand(validBalProject, printStream, printStream, false); - new CommandLine(pushCommand).parse(args); + new CommandLine(pushCommand).parseArgs(args); pushCommand.execute(); Assert.assertTrue(readOutput().contains("ballerina-push - Push the Ballerina Archive (BALA)")); @@ -333,17 +336,17 @@ public void testPushCommandWithHelp() throws IOException { @Test public void testPushToCustomRepo() throws IOException { - Path validBalProject = Paths.get("build").resolve("validProjectWithTarget"); + Path validBalProject = Path.of("build/validProjectWithTarget"); FileUtils.copyDirectory( this.testResources.resolve("validProjectWithTarget").toFile(), validBalProject.toFile()); FileUtils.moveDirectory( validBalProject.resolve("target-dir").toFile(), validBalProject.resolve("target").toFile()); - Path mockRepo = Paths.get("build").resolve("ballerina-home"); + Path mockRepo = Path.of("build/ballerina-home"); // Test if no arguments was passed in String[] args = { "--repository=local" }; PushCommand pushCommand = new PushCommand(validBalProject, printStream, printStream, false); - new CommandLine(pushCommand).parse(args); + new CommandLine(pushCommand).parseArgs(args); try (MockedStatic repoUtils = Mockito.mockStatic(RepoUtils.class)) { repoUtils.when(RepoUtils::createAndGetHomeReposPath).thenReturn(mockRepo); repoUtils.when(RepoUtils::getBallerinaShortVersion).thenReturn("1.0.0"); @@ -352,8 +355,7 @@ public void testPushToCustomRepo() throws IOException { } try { - ProjectFiles.validateBalaProjectPath(mockRepo.resolve("repositories").resolve("local").resolve("bala") - .resolve("foo").resolve("winery").resolve("0.1.0").resolve("any")); + ProjectFiles.validateBalaProjectPath(mockRepo.resolve("repositories/local/bala/foo/winery/0.1.0/any")); } catch (ProjectException e) { Assert.fail(e.getMessage()); } @@ -366,16 +368,15 @@ public void testPushWithoutPackageMd() throws IOException { // Pack project PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); - new CommandLine(packCommand).parse(); + new CommandLine(packCommand).parseArgs(); packCommand.execute(); - Assert.assertTrue( - projectPath.resolve("target").resolve("bala").resolve("foo-winery-any-0.1.0.bala").toFile().exists()); + Assert.assertTrue(projectPath.resolve("target/bala/foo-winery-any-0.1.0.bala").toFile().exists()); // Push String expected = "Package.md is missing in bala file"; PushCommand pushCommand = new PushCommand(projectPath, printStream, printStream, false); - new CommandLine(pushCommand).parse(); + new CommandLine(pushCommand).parseArgs(); pushCommand.execute(); String buildLog = readOutput(true); @@ -391,10 +392,9 @@ public void testPushWithEmptyPackageMd() throws IOException { // Pack project PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); - new CommandLine(packCommand).parse(); + new CommandLine(packCommand).parseArgs(); packCommand.execute(); - Assert.assertTrue( - projectPath.resolve("target").resolve("bala").resolve("foo-winery-any-0.1.0.bala").toFile().exists()); + Assert.assertTrue(projectPath.resolve("target/bala/foo-winery-any-0.1.0.bala").toFile().exists()); Files.delete(projectPath.resolve(ProjectConstants.PACKAGE_MD_FILE_NAME)); @@ -402,7 +402,7 @@ public void testPushWithEmptyPackageMd() throws IOException { String expected = "md file cannot be empty"; PushCommand pushCommand = new PushCommand(projectPath, printStream, printStream, false); - new CommandLine(pushCommand).parse(); + new CommandLine(pushCommand).parseArgs(); pushCommand.execute(); String buildLog = readOutput(true); @@ -415,14 +415,13 @@ public void testPushToAnUnsupportedRepo() throws IOException { Path projectPath = this.testResources.resolve("validLibraryProject"); // Build project PackCommand packCommand = new PackCommand(projectPath, printStream, printStream, false, true); - new CommandLine(packCommand).parse(); + new CommandLine(packCommand).parseArgs(); packCommand.execute(); - Assert.assertTrue( - projectPath.resolve("target").resolve("bala").resolve("foo-winery-any-0.1.0.bala").toFile().exists()); + Assert.assertTrue(projectPath.resolve("target/bala/foo-winery-any-0.1.0.bala").toFile().exists()); String[] args = { "--repository=stdlib.local" }; PushCommand pushCommand = new PushCommand(projectPath, printStream, printStream, false); - new CommandLine(pushCommand).parse(args); + new CommandLine(pushCommand).parseArgs(args); pushCommand.execute(); String errMsg = "unsupported repository 'stdlib.local' found. Only 'local' repository and repositories " + "mentioned in the Settings.toml are supported."; diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/RunBuildToolsTaskTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/RunBuildToolsTaskTest.java index 2c12bdcc081c..80f7efef4e41 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/RunBuildToolsTaskTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/RunBuildToolsTaskTest.java @@ -18,6 +18,7 @@ package io.ballerina.cli.cmd; +import io.ballerina.cli.launcher.BLauncherException; import io.ballerina.cli.task.RunBuildToolsTask; import io.ballerina.projects.BuildOptions; import io.ballerina.projects.Project; @@ -27,6 +28,7 @@ import org.mockito.MockedStatic; import org.mockito.Mockito; import org.testng.Assert; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -35,7 +37,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; +import java.util.List; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; @@ -49,21 +51,27 @@ */ public class RunBuildToolsTaskTest extends BaseCommandTest { private Path buildToolResources; - private static final Path testBuildDirectory = Paths.get("build").toAbsolutePath(); + private static final Path testBuildDirectory = Path.of("build").toAbsolutePath(); private static final Path testDistCacheDirectory = testBuildDirectory.resolve(DIST_CACHE_DIRECTORY); Path mockCentralBalaDirPath = testDistCacheDirectory.resolve("bala"); private static final long TWO_DAYS = 2 * 24 * 60 * 60 * 1000; private static final long HALF_DAY = 12 * 60 * 60 * 1000; + private static final Path LOG_FILE = Path.of("build/logs/log_creator_combined_plugin/compiler-plugin.txt") + .toAbsolutePath(); + + @Override @BeforeClass public void setup() throws IOException { super.setup(); + Files.createDirectories(LOG_FILE.getParent()); + Files.writeString(LOG_FILE, ""); // copy all test resources try { Path testResources = super.tmpDir.resolve("build-tool-test-resources"); this.buildToolResources = testResources.resolve("buildToolResources"); - Path testResourcesPath = Paths.get( + Path testResourcesPath = Path.of( Objects.requireNonNull(getClass().getClassLoader().getResource("test-resources")).toURI()); Files.walkFileTree(testResourcesPath, new BuildCommandTest.Copy(testResourcesPath, testResources)); } catch (Exception e) { @@ -88,7 +96,7 @@ public void setup() throws IOException { } @Test(description = "Resolve a tool offline", dataProvider = "buildToolOfflineProvider") - public void testOfflineToolResolution(String projectName, String outputFileName, boolean sticky) + public void testOfflineToolResolution(String projectName, String outputFileName, boolean sticky, boolean isError) throws IOException { Path projectPath = buildToolResources.resolve(projectName); Project project = BuildProject.load(projectPath, @@ -97,10 +105,21 @@ public void testOfflineToolResolution(String projectName, String outputFileName, try (MockedStatic repoUtils = Mockito.mockStatic( BuildToolUtils.class, Mockito.CALLS_REAL_METHODS)) { repoUtils.when(BuildToolUtils::getCentralBalaDirPath).thenReturn(mockCentralBalaDirPath); - runBuildToolsTask.execute(project); + try { + runBuildToolsTask.execute(project); + } catch (BLauncherException e) { + if (!isError) { + String errorMsg = "Error executing build tools task for project: " + projectName + + (sticky ? "with sticky." : "without sticky. ") + e.getMessage(); + Assert.fail(errorMsg); + } + List messages = e.getMessages(); + Assert.assertEquals(messages.size(), 1); + Assert.assertEquals(messages.get(0), "error: build tool execution contains errors"); + } } String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput(outputFileName)); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput(outputFileName)); } @Test(description = "Generate files using a project and find the generated file in project instance") @@ -114,7 +133,7 @@ public void testProjectForAddedGeneratedCode() throws IOException { runBuildToolsTask.execute(project); } String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-tool-generate-file.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("build-tool-generate-file.txt")); AtomicBoolean fileFound = new AtomicBoolean(false); project.currentPackage().modules().forEach(module -> { if (module.moduleName().toString().equals("winery.mod_generate")) { @@ -135,83 +154,98 @@ public Object[][] buildToolOfflineProvider() { { "project-with-central-build-tool", "build-tool-offline.txt", + false, false }, { "project-with-non-existent-build-tool", "build-tool-offline-resolve-failed.txt", - false + false, + true }, { "fresh-project-with-central-build-tool", "build-tool-offline-resolve-failed-wo-version.txt", - false + false, + true, }, { "project-with-2.x-central-build-tool", "build-tool-offline-with-new-major-version-locked.txt", - false + false, + true }, { "project-with-non-existent-subcommand", "build-tool-non-existent-subcommand.txt", + false, false }, { "project-with-invalid-name-build-tool", "build-tool-invalid-name.txt", + false, false }, { "project-with-multilevel-subcommands", "build-tool-multilevel-subcommands.txt", + false, false }, { "project-with-only-subcommands", "build-tool-only-subcommands.txt", + false, false }, { "project-with-hidden-commands", "build-tool-hidden-commands.txt", + false, false }, { "project-with-missing-interface-build-tool", "build-tool-missing-interface.txt", + false, false }, { "project-with-no-options-build-tool", "build-tool-no-options.txt", + false, false }, { "project-with-old-build-tool", "build-tool-without-sticky.txt", + false, false }, { "project-with-old-build-tool", "build-tool-with-sticky.txt", + true, true }, { "project-lt-24h-with-build-tool", "build-tool-lt-24-build-file.txt", - false + false, + true }, { "project-gt-24h-with-build-tool", "build-tool-gt-24-build-file.txt", + false, false }, }; } private void addBuildJsonToProjects(String projectName, long time) { - Path buildJsonPath = buildToolResources.resolve(projectName).resolve("target").resolve("build"); + Path buildJsonPath = buildToolResources.resolve(projectName).resolve("target/build"); String buildJsonContent = "{\n" + " \"last_build_time\": 1710907945705,\n" + " \"last_update_time\": " + time + ",\n" + @@ -227,4 +261,11 @@ private void addBuildJsonToProjects(String projectName, long time) { Assert.fail("Error writing build.json file"); } } + + @AfterClass + public void cleanUp() throws IOException { + Files.deleteIfExists(LOG_FILE); + Files.deleteIfExists(LOG_FILE.getParent()); + Files.deleteIfExists(LOG_FILE.getParent().getParent()); + } } diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/RunCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/RunCommandTest.java index b676e08347b7..b7b7e7ff667c 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/RunCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/RunCommandTest.java @@ -5,27 +5,34 @@ import io.ballerina.projects.ProjectEnvironmentBuilder; import io.ballerina.projects.environment.Environment; import io.ballerina.projects.environment.EnvironmentBuilder; +import io.ballerina.projects.util.BuildToolUtils; import io.ballerina.projects.util.ProjectUtils; import org.apache.commons.io.filefilter.WildcardFileFilter; import org.ballerinalang.test.BCompileUtil; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeSuite; import org.testng.annotations.Test; +import org.wso2.ballerinalang.util.RepoUtils; import picocli.CommandLine; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileFilter; import java.io.IOException; +import java.io.PrintStream; import java.net.URI; import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; +import java.util.List; import java.util.Objects; import static io.ballerina.cli.cmd.CommandOutputUtils.getOutput; +import static io.ballerina.cli.cmd.CommandOutputUtils.replaceDependenciesTomlContent; import static io.ballerina.projects.util.ProjectConstants.DIST_CACHE_DIRECTORY; import static io.ballerina.projects.util.ProjectConstants.USER_DIR_PROPERTY; @@ -38,8 +45,7 @@ public class RunCommandTest extends BaseCommandTest { private Path testResources; private Path testDistCacheDirectory; private ProjectEnvironmentBuilder projectEnvironmentBuilder; - static Path logFile = Paths.get("./src/test/resources/compiler_plugin_tests/" + - "log_creator_combined_plugin/compiler-plugin.txt"); + static Path logFile = Path.of("build/logs/log_creator_combined_plugin/compiler-plugin.txt").toAbsolutePath(); @BeforeSuite public void setupSuite() throws IOException { @@ -47,33 +53,34 @@ public void setupSuite() throws IOException { Files.writeString(logFile, ""); } + @Override @BeforeClass public void setup() throws IOException { super.setup(); try { this.testResources = super.tmpDir.resolve("build-test-resources"); - Path testBuildDirectory = Paths.get("build").toAbsolutePath(); + Path testBuildDirectory = Path.of("build").toAbsolutePath(); this.testDistCacheDirectory = testBuildDirectory.resolve(DIST_CACHE_DIRECTORY); - Path customUserHome = Paths.get("build", "user-home"); + Path customUserHome = Path.of("build", "user-home"); Environment environment = EnvironmentBuilder.getBuilder().setUserHome(customUserHome).build(); this.projectEnvironmentBuilder = ProjectEnvironmentBuilder.getBuilder(environment); URI testResourcesURI = Objects.requireNonNull( getClass().getClassLoader().getResource("test-resources")).toURI(); - Files.walkFileTree(Paths.get(testResourcesURI), new BuildCommandTest.Copy(Paths.get(testResourcesURI), + Files.walkFileTree(Path.of(testResourcesURI), new BuildCommandTest.Copy(Path.of(testResourcesURI), this.testResources)); } catch (URISyntaxException e) { Assert.fail("error loading resources"); } } - @Test(description = "Run a valid ballerina file") - public void testRunValidBalFile() throws IOException { - Path validBalFilePath = this.testResources.resolve("valid-run-bal-file").resolve("file_create.bal"); + @Test(description = "Run a valid ballerina file", dataProvider = "optimizeDependencyCompilation") + public void testRunValidBalFile(Boolean optimizeDependencyCompilation) throws IOException { + Path validBalFilePath = this.testResources.resolve("valid-run-bal-file/file_create.bal"); System.setProperty("user.dir", this.testResources.resolve("valid-run-bal-file").toString()); - Path tempFile = this.testResources.resolve("valid-run-bal-file").resolve("temp.txt"); + Path tempFile = this.testResources.resolve("valid-run-bal-file/temp.txt"); // set valid source root - RunCommand runCommand = new RunCommand(validBalFilePath, printStream, false); + RunCommand runCommand = new RunCommand(validBalFilePath, printStream, false, optimizeDependencyCompilation); // name of the file as argument new CommandLine(runCommand).setEndOfOptionsDelimiter("").setUnmatchedOptionsArePositionalParams(true) .parseArgs(validBalFilePath.toString(), "--", tempFile.toString()); @@ -82,7 +89,7 @@ public void testRunValidBalFile() throws IOException { runCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("run-bal.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("run-bal.txt")); Assert.assertTrue(tempFile.toFile().exists()); @@ -92,23 +99,20 @@ public void testRunValidBalFile() throws IOException { @Test(description = "Run non existing bal file") public void testRunNonExistingBalFile() throws IOException { // valid source root path - Path validBalFilePath = this.testResources.resolve("valid-run-bal-file").resolve("xyz.bal"); + Path validBalFilePath = this.testResources.resolve("valid-run-bal-file/xyz.bal"); RunCommand runCommand = new RunCommand(validBalFilePath, printStream, false); - // non existing bal file new CommandLine(runCommand).parseArgs(validBalFilePath.toString()); runCommand.execute(); String buildLog = readOutput(true); - Assert.assertTrue(buildLog.replaceAll("\r", "") + Assert.assertTrue(buildLog.replace("\r", "") .contains("The file does not exist: " + validBalFilePath)); - } @Test(description = "Run bal file containing syntax error") public void testRunBalFileWithSyntaxError() { // valid source root path - Path balFilePath = this.testResources.resolve("bal-file-with-syntax-error").resolve("hello_world.bal"); + Path balFilePath = this.testResources.resolve("bal-file-with-syntax-error/hello_world.bal"); RunCommand runCommand = new RunCommand(balFilePath, printStream, false); - // non existing bal file new CommandLine(runCommand).parseArgs(balFilePath.toString()); try { runCommand.execute(); @@ -122,7 +126,6 @@ public void testRunBalProjectWithSyntaxError() { // valid source root path Path balFilePath = this.testResources.resolve("bal-project-with-syntax-error"); RunCommand runCommand = new RunCommand(balFilePath, printStream, false); - // non existing bal file new CommandLine(runCommand).parseArgs(balFilePath.toString()); try { runCommand.execute(); @@ -149,14 +152,15 @@ public void testRunValidBalProject() throws IOException { Files.delete(tempFile); } - @Test(description = "Run a valid ballerina project from the project directory") - public void testRunValidBalProjectFromProjectDir() throws IOException { + @Test(description = "Run a valid ballerina project from the project directory", + dataProvider = "optimizeDependencyCompilation") + public void testRunValidBalProjectFromProjectDir(Boolean optimizeDependencyCompilation) throws IOException { Path projectPath = this.testResources.resolve("validRunProject"); Path tempFile = projectPath.resolve("temp.txt"); System.setProperty("user.dir", this.testResources.resolve("validRunProject").toString()); // set valid source root - RunCommand runCommand = new RunCommand(projectPath, printStream, false); + RunCommand runCommand = new RunCommand(projectPath, printStream, false, optimizeDependencyCompilation); // name of the file as argument new CommandLine(runCommand).setEndOfOptionsDelimiter("").setUnmatchedOptionsArePositionalParams(true) .parseArgs("--", tempFile.toString()); @@ -168,15 +172,15 @@ public void testRunValidBalProjectFromProjectDir() throws IOException { Files.delete(tempFile); } - @Test(description = "Run a project with a build tool execution") - public void testRunProjectWithBuildTool() throws IOException { + @Test(description = "Run a project with a build tool execution", dataProvider = "optimizeDependencyCompilation") + public void testRunProjectWithBuildTool(Boolean optimizeDependencyCompilation) throws IOException { Path projectPath = this.testResources.resolve("proper-build-tool"); System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); - RunCommand runCommand = new RunCommand(projectPath, printStream, false); + RunCommand runCommand = new RunCommand(projectPath, printStream, false, optimizeDependencyCompilation); new CommandLine(runCommand).parseArgs(); runCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("run-project-with-build-tool.txt")); } @@ -198,11 +202,12 @@ public void testRunCommandWithInvalidArg() { } } - @Test(description = "Run a valid ballerina file that has an import having platform libs") - public void testRunProjectContainingImportsWithPlatformLibs() { + @Test(description = "Run a valid ballerina file that has an import having platform libs", + dataProvider = "optimizeDependencyCompilation") + public void testRunProjectContainingImportsWithPlatformLibs(Boolean optimizeDependencyCompilation) { Path projectPath = this.testResources.resolve("validRunProjectImportsWithPlatformLibs"); // set valid source root - RunCommand runCommand = new RunCommand(projectPath, printStream, false); + RunCommand runCommand = new RunCommand(projectPath, printStream, false, optimizeDependencyCompilation); // name of the file as argument new CommandLine(runCommand).parseArgs(projectPath.toString()); @@ -235,7 +240,7 @@ public void testRunJarFile() { // Run build command to generate jar file BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false); buildCommand.execute(); - Assert.assertTrue(projectPath.resolve("target").resolve("bin").resolve("foo.jar").toFile().exists()); + Assert.assertTrue(projectPath.resolve("target/bin/foo.jar").toFile().exists()); // Try to run the har file Path tempFile = projectPath.resolve("foo.jar"); @@ -264,7 +269,7 @@ public void testHeapDumpGenerationForOOM() { runCommand.execute(); } catch (RuntimePanicException e) { File projectDir = new File(projectPath.toString()); - FileFilter fileFilter = new WildcardFileFilter("java_pid*.hprof"); + FileFilter fileFilter = WildcardFileFilter.builder().setWildcards("java_pid*.hprof").get(); Assert.assertTrue(Objects.requireNonNull(projectDir.listFiles(fileFilter)).length > 0); } } @@ -278,25 +283,21 @@ public void testRunWithCustomTarget() { RunCommand runCommand = new RunCommand(projectPath, printStream, false, customTargetDir); runCommand.execute(); Assert.assertTrue(Files.exists(customTargetDir.resolve("cache"))); - Assert.assertTrue(Files.exists(customTargetDir.resolve("cache").resolve("wso2").resolve("foo").resolve("0.1" + - ".0"))); - Assert.assertTrue(Files.exists(customTargetDir.resolve("cache").resolve("wso2").resolve("foo").resolve("0.1" + - ".0"))); - if (!(Files.exists(customTargetDir.resolve("cache").resolve("wso2").resolve("foo").resolve("0.1" + - ".0").resolve("java17").resolve("wso2-foo-0.1.0.jar")) || Files.exists(customTargetDir.resolve( - "cache").resolve("wso2").resolve("foo").resolve("0.1" + - ".0").resolve("any").resolve("wso2-foo-0.1.0.jar")))) { + Assert.assertTrue(Files.exists(customTargetDir.resolve("cache/wso2/foo/0.1.0"))); + Assert.assertTrue(Files.exists(customTargetDir.resolve("cache/wso2/foo/0.1.0"))); + if (!(Files.exists(customTargetDir.resolve("cache/wso2/foo/0.1.0/java17/wso2-foo-0.1.0.jar")) || + Files.exists(customTargetDir.resolve("cache/wso2/foo/0.1.0/any/wso2-foo-0.1.0.jar")))) { Assert.fail("Run command with custom target dir failed"); } } - @Test(description = "Run a ballerina project with the engagement of all type of compiler plugins") - public void testRunBalProjectWithAllCompilerPlugins() throws IOException { - Path logFile = Paths.get("./src/test/resources/compiler_plugin_tests/" + - "log_creator_combined_plugin/compiler-plugin.txt"); + @Test(description = "Run a ballerina project with the engagement of all type of compiler plugins", + dataProvider = "optimizeDependencyCompilation") + public void testRunBalProjectWithAllCompilerPlugins(Boolean optimizeDependencyCompilation) throws IOException { + Path logFile = Path.of("build/logs/log_creator_combined_plugin/compiler-plugin.txt").toAbsolutePath(); Files.createDirectories(logFile.getParent()); Files.writeString(logFile, ""); - Path compilerPluginPath = Paths.get("./src/test/resources/test-resources").resolve("compiler-plugins"); + Path compilerPluginPath = Path.of("./src/test/resources/test-resources/compiler-plugins"); BCompileUtil.compileAndCacheBala(compilerPluginPath.resolve("log_creator_pkg_provided_code_analyzer_im"), testDistCacheDirectory, projectEnvironmentBuilder); BCompileUtil.compileAndCacheBala(compilerPluginPath.resolve("log_creator_pkg_provided_code_generator_im"), @@ -304,9 +305,9 @@ public void testRunBalProjectWithAllCompilerPlugins() throws IOException { BCompileUtil.compileAndCacheBala(compilerPluginPath.resolve("log_creator_pkg_provided_code_modifier_im"), testDistCacheDirectory, projectEnvironmentBuilder); - Path projectPath = this.testResources.resolve("compiler-plugins").resolve("log_creator_combined_plugin"); + Path projectPath = this.testResources.resolve("compiler-plugins/log_creator_combined_plugin"); System.setProperty("user.dir", projectPath.toString()); - RunCommand runCommand = new RunCommand(projectPath, printStream, false); + RunCommand runCommand = new RunCommand(projectPath, printStream, false, optimizeDependencyCompilation); new CommandLine(runCommand).parseArgs(); runCommand.execute(); String logFileContent = Files.readString(logFile); @@ -357,8 +358,8 @@ public void testRunBalProjectWithDumpGraphFlag() throws IOException { Path projectPath = dumpGraphResourcePath.resolve("package_a"); System.setProperty("user.dir", projectPath.toString()); - java.io.ByteArrayOutputStream out = new java.io.ByteArrayOutputStream(); - System.setOut(new java.io.PrintStream(out)); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + System.setOut(new PrintStream(out)); RunCommand runCommand = new RunCommand(projectPath, printStream, false); new CommandLine(runCommand).parseArgs("--dump-graph"); @@ -366,9 +367,8 @@ public void testRunBalProjectWithDumpGraphFlag() throws IOException { String buildLog = readOutput(true).replaceAll("\r", "").strip(); Assert.assertEquals(buildLog, getOutput("run-project-with-dump-graph.txt")); - Assert.assertTrue(projectPath.resolve("target").resolve("cache").resolve("foo") - .resolve("package_a").resolve("0.1.0").resolve("java17") - .resolve("foo-package_a-0.1.0.jar").toFile().exists()); + Assert.assertTrue(projectPath.resolve("target/cache/foo/package_a/0.1.0/java17/foo-package_a-0.1.0.jar") + .toFile().exists()); ProjectUtils.deleteDirectory(projectPath.resolve("target")); } @@ -390,9 +390,8 @@ public void testRunBalProjectWithDumpRawGraphsFlag() throws IOException { String buildLog = readOutput(true).replaceAll("\r", "").strip(); Assert.assertEquals(buildLog, getOutput("run-project-with-dump-raw-graphs.txt")); - Assert.assertTrue(projectPath.resolve("target").resolve("cache").resolve("foo") - .resolve("package_a").resolve("0.1.0").resolve("java17") - .resolve("foo-package_a-0.1.0.jar").toFile().exists()); + Assert.assertTrue(projectPath.resolve("target/cache/foo/package_a/0.1.0/java17/foo-package_a-0.1.0.jar") + .toFile().exists()); ProjectUtils.deleteDirectory(projectPath.resolve("target")); } @@ -404,10 +403,33 @@ public void testRunEmptyPackage() throws IOException { RunCommand runCommand = new RunCommand(projectPath, printStream, false); new CommandLine(runCommand).parseArgs(); - runCommand.execute(); + try { + runCommand.execute(); + } catch (BLauncherException e) { + List messages = e.getMessages(); + Assert.assertEquals(messages.size(), 1); + Assert.assertEquals(messages.get(0), getOutput("build-empty-package.txt")); + } + } + @Test(description = "Run an empty package with code generator build tools") + public void testRunEmptyProjectWithBuildTools() throws IOException { + BCompileUtil.compileAndCacheBala( + testResources.resolve("buildToolResources/tools/ballerina-generate-file").toString(), + testDistCacheDirectory, projectEnvironmentBuilder); + Path projectPath = this.testResources.resolve("emptyProjectWithBuildTool"); + replaceDependenciesTomlContent(projectPath, "**INSERT_DISTRIBUTION_VERSION_HERE**", + RepoUtils.getBallerinaShortVersion()); + System.setProperty(USER_DIR_PROPERTY, projectPath.toString()); + try (MockedStatic repoUtils = Mockito.mockStatic( + BuildToolUtils.class, Mockito.CALLS_REAL_METHODS)) { + repoUtils.when(BuildToolUtils::getCentralBalaDirPath).thenReturn(testDistCacheDirectory.resolve("bala")); + RunCommand runCommand = new RunCommand(projectPath, printStream, false); + new CommandLine(runCommand).parseArgs(); + runCommand.execute(); + } String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-empty-package.txt")); + Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("run-empty-project-with-build-tools.txt")); } @AfterSuite diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/SearchCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/SearchCommandTest.java index 6d92ef9b0446..8dd3e57815d7 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/SearchCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/SearchCommandTest.java @@ -34,11 +34,11 @@ public class SearchCommandTest extends BaseCommandTest { @Test(description = "Search without keyword") public void testSearchWithoutKeyword() throws IOException { SearchCommand searchCommand = new SearchCommand(printStream, printStream, false); - new CommandLine(searchCommand).parse(); + new CommandLine(searchCommand).parseArgs(); searchCommand.execute(); String buildLog = readOutput(true); - String actual = buildLog.replaceAll("\r", ""); + String actual = buildLog.replace("\r", ""); Assert.assertTrue(actual.contains("ballerina: no keyword given")); Assert.assertTrue(actual.contains("bal search [||]")); } @@ -46,11 +46,11 @@ public void testSearchWithoutKeyword() throws IOException { @Test(description = "Search with too many args") public void testPullWithTooManyArgs() throws IOException { SearchCommand searchCommand = new SearchCommand(printStream, printStream, false); - new CommandLine(searchCommand).parse("wso2", "tests"); + new CommandLine(searchCommand).parseArgs("wso2", "tests"); searchCommand.execute(); String buildLog = readOutput(true); - String actual = buildLog.replaceAll("\r", ""); + String actual = buildLog.replace("\r", ""); Assert.assertTrue(actual.contains("ballerina: too many arguments")); Assert.assertTrue(actual.contains("bal search [||]")); } @@ -60,7 +60,7 @@ public void testSearchCommandArgAndHelp() throws IOException { // Test if no arguments was passed in String[] args = { "sample2", "--help" }; SearchCommand searchCommand = new SearchCommand(printStream, printStream, false); - new CommandLine(searchCommand).parse(args); + new CommandLine(searchCommand).parseArgs(args); searchCommand.execute(); Assert.assertTrue(readOutput().contains("ballerina-search - Search Ballerina Central for packages")); @@ -71,7 +71,7 @@ public void testSearchCommandWithHelp() throws IOException { // Test if no arguments was passed in String[] args = { "-h" }; SearchCommand searchCommand = new SearchCommand(printStream, printStream, false); - new CommandLine(searchCommand).parse(args); + new CommandLine(searchCommand).parseArgs(args); searchCommand.execute(); Assert.assertTrue(readOutput().contains("ballerina-search - Search Ballerina Central for packages")); diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/ShellCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/ShellCommandTest.java index ce865e817847..8978967e502e 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/ShellCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/ShellCommandTest.java @@ -22,6 +22,7 @@ import io.ballerina.shell.cli.ReplShellApplication; import org.jline.reader.EndOfFileException; import org.testng.Assert; +import org.testng.SkipException; import org.testng.annotations.Test; import java.io.BufferedReader; @@ -36,6 +37,8 @@ import java.util.List; import java.util.Objects; +import static io.ballerina.cli.utils.OsUtils.isWindows; + /** * Shell command tests. * @@ -63,14 +66,17 @@ public void testShellCommandFail() throws IOException { // Does not give the prompt Assert.assertFalse(baos.toString().endsWith("=$ ")); // Exit because home dir err - Assert.assertEquals(readOutput().trim(), "" + - "something went wrong while executing REPL: " + + Assert.assertEquals(readOutput().replace("\\", "/").trim(), "something went wrong while executing REPL: " + "io.ballerina.projects.ProjectException: Ballerina distribution directory does not exists in `" + "not/existing/dir/abc'"); } @Test public void testShellExecution() throws Exception { + if (isWindows()) { + throw new SkipException("Currently failing on Windows"); + } + List testCases = new ArrayList<>(); testCases.add(new String[]{"int i = 35", ""}); testCases.add(new String[]{"i*2 + 10", "80\n"}); @@ -104,7 +110,7 @@ public void testShellExecution() throws Exception { shellPrompt, testCase[0], testCase[1], shellPrompt); Assert.assertEquals(filteredString(exprResponse), filteredString(expectedExprResponse)); } - } catch (IOException | InterruptedException ignored) { + } catch (IOException ignored) { } }); testIntegratorThread.start(); @@ -131,7 +137,7 @@ private String readResponse(BufferedReader stream, String shellPrompt) throws IO return data.toString(); } - private void sendRequest(PrintStream stream, String string) throws InterruptedException { + private void sendRequest(PrintStream stream, String string) { stream.append(string); stream.println(System.lineSeparator()); stream.flush(); diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/TestCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/TestCommandTest.java index 8c8828dc0eb1..d8234d9fecda 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/TestCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/TestCommandTest.java @@ -23,40 +23,51 @@ import io.ballerina.projects.ProjectEnvironmentBuilder; import io.ballerina.projects.environment.Environment; import io.ballerina.projects.environment.EnvironmentBuilder; +import io.ballerina.projects.util.BuildToolUtils; import io.ballerina.projects.util.ProjectConstants; import io.ballerina.projects.util.ProjectUtils; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.filefilter.WildcardFileFilter; import org.ballerinalang.test.BCompileUtil; +import org.ballerinalang.test.runtime.util.TesterinaConstants; import org.mockito.MockedStatic; import org.mockito.Mockito; import org.testng.Assert; +import org.testng.SkipException; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import org.wso2.ballerinalang.util.RepoUtils; import picocli.CommandLine; +import java.io.BufferedReader; import java.io.File; import java.io.FileFilter; import java.io.IOException; +import java.io.InputStreamReader; import java.net.URI; import java.net.URISyntaxException; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Objects; +import java.util.stream.Stream; import static io.ballerina.cli.cmd.CommandOutputUtils.getOutput; import static io.ballerina.cli.cmd.CommandOutputUtils.readFileAsString; +import static io.ballerina.cli.cmd.CommandOutputUtils.replaceDependenciesTomlContent; +import static io.ballerina.cli.utils.OsUtils.isWindows; import static io.ballerina.projects.util.ProjectConstants.BUILD_FILE; import static io.ballerina.projects.util.ProjectConstants.DEPENDENCIES_TOML; import static io.ballerina.projects.util.ProjectConstants.DIST_CACHE_DIRECTORY; import static io.ballerina.projects.util.ProjectConstants.RESOURCE_DIR_NAME; import static io.ballerina.projects.util.ProjectConstants.TARGET_DIR_NAME; +import static io.ballerina.projects.util.ProjectConstants.TEST_RUNTIME_MAIN_ARGS_FILE; import static io.ballerina.projects.util.ProjectConstants.USER_DIR_PROPERTY; /** @@ -69,32 +80,33 @@ public class TestCommandTest extends BaseCommandTest { private Path testDistCacheDirectory; ProjectEnvironmentBuilder projectEnvironmentBuilder; + @Override @BeforeClass public void setup() throws IOException { super.setup(); try { this.testResources = super.tmpDir.resolve("test-cmd-test-resources"); - Path testBuildDirectory = Paths.get("build").toAbsolutePath(); + Path testBuildDirectory = Path.of("build").toAbsolutePath(); this.testDistCacheDirectory = testBuildDirectory.resolve(DIST_CACHE_DIRECTORY); - Path customUserHome = Paths.get("build", "user-home"); + Path customUserHome = Path.of("build/user-home"); Environment environment = EnvironmentBuilder.getBuilder().setUserHome(customUserHome).build(); projectEnvironmentBuilder = ProjectEnvironmentBuilder.getBuilder(environment); URI testResourcesURI = Objects.requireNonNull( getClass().getClassLoader().getResource("test-resources")).toURI(); - Files.walkFileTree(Paths.get(testResourcesURI), new TestCommandTest.Copy(Paths.get(testResourcesURI), + Files.walkFileTree(Path.of(testResourcesURI), new TestCommandTest.Copy(Path.of(testResourcesURI), this.testResources)); } catch (URISyntaxException e) { Assert.fail("error loading resources"); } } - @Test(description = "Test a valid ballerina file") - public void testTestBalFile() { - Path validBalFilePath = this.testResources.resolve("valid-test-bal-file").resolve("sample_tests.bal"); + @Test(description = "Test a valid ballerina file", dataProvider = "optimizeDependencyCompilation") + public void testTestBalFile(Boolean optimizeDependencyCompilation) { + Path validBalFilePath = this.testResources.resolve("valid-test-bal-file/sample_tests.bal"); System.setProperty(ProjectConstants.USER_DIR, this.testResources.resolve("valid-test-bal-file").toString()); // set valid source root - TestCommand testCommand = new TestCommand(validBalFilePath, false); + TestCommand testCommand = new TestCommand(validBalFilePath, false, optimizeDependencyCompilation); // name of the file as argument new CommandLine(testCommand).parseArgs(validBalFilePath.toString()); testCommand.execute(); @@ -102,7 +114,7 @@ public void testTestBalFile() { @Test(description = "Test a valid ballerina file with periods in the file name") public void testTestBalFileWithPeriods() { - Path validBalFilePath = this.testResources.resolve("valid-test-bal-file").resolve("sample.tests.bal"); + Path validBalFilePath = this.testResources.resolve("valid-test-bal-file/sample.tests.bal"); System.setProperty(ProjectConstants.USER_DIR, this.testResources.resolve("valid-test-bal-file").toString()); // set valid source root @@ -114,26 +126,25 @@ public void testTestBalFileWithPeriods() { @Test(description = "Test non .bal file") public void testNonBalFileTest() throws IOException { - Path nonBalFilePath = this.testResources.resolve("non-bal-file").resolve("hello_world.txt"); + Path nonBalFilePath = this.testResources.resolve("non-bal-file/hello_world.txt"); TestCommand testCommand = new TestCommand(nonBalFilePath, printStream, printStream, false); new CommandLine(testCommand).parseArgs(nonBalFilePath.toString()); testCommand.execute(); String buildLog = readOutput(true); - Assert.assertTrue(buildLog.replaceAll("\r", "") + Assert.assertTrue(buildLog.replace("\r", "") .contains("Invalid Ballerina source file(.bal): " + nonBalFilePath)); } @Test(description = "Test non existing bal file") public void testNonExistingBalFile() throws IOException { // valid source root path - Path validBalFilePath = this.testResources.resolve("valid-non-bal-file").resolve("xyz.bal"); + Path validBalFilePath = this.testResources.resolve("valid-non-bal-file/xyz.bal"); TestCommand testCommand = new TestCommand(validBalFilePath, printStream, printStream, false); - // non existing bal file new CommandLine(testCommand).parseArgs(validBalFilePath.toString()); testCommand.execute(); String buildLog = readOutput(true); - Assert.assertTrue(buildLog.replaceAll("\r", "") + Assert.assertTrue(buildLog.replace("\r", "") .contains("The file does not exist: " + validBalFilePath)); } @@ -141,9 +152,8 @@ public void testNonExistingBalFile() throws IOException { @Test(description = "Test bal file containing syntax error") public void testBalFileWithSyntaxError() { // valid source root path - Path balFilePath = this.testResources.resolve("bal-file-with-syntax-error").resolve("sample_tests.bal"); + Path balFilePath = this.testResources.resolve("bal-file-with-syntax-error/sample_tests.bal"); TestCommand testCommand = new TestCommand(balFilePath, printStream, printStream, false); - // non existing bal file new CommandLine(testCommand).parseArgs(balFilePath.toString()); try { testCommand.execute(); @@ -157,11 +167,10 @@ public void testBuildProjectWithTests() throws IOException { Path projectPath = this.testResources.resolve("validProjectWithTests"); System.setProperty(ProjectConstants.USER_DIR, projectPath.toString()); TestCommand testCommand = new TestCommand(projectPath, printStream, printStream, false); - // non existing bal file new CommandLine(testCommand).parseArgs(); testCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("test-project.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("test-project.txt")); } @Test(description = "Build a valid ballerina project") @@ -169,7 +178,6 @@ public void testBuildMultiModuleProject() { Path projectPath = this.testResources.resolve("validMultiModuleProjectWithTests"); System.setProperty(ProjectConstants.USER_DIR, projectPath.toString()); TestCommand testCommand = new TestCommand(projectPath, printStream, printStream, false); - // non existing bal file new CommandLine(testCommand).parseArgs(); testCommand.execute(); } @@ -178,11 +186,10 @@ public void testBuildMultiModuleProject() { public void testTestBalProjectFromADifferentDirectory() throws IOException { Path projectPath = this.testResources.resolve("validProjectWithTests"); TestCommand buildCommand = new TestCommand(projectPath, printStream, printStream, false); - // non existing bal file new CommandLine(buildCommand).parseArgs(projectPath.toString()); buildCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("test-project.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("test-project.txt")); } @Test(description = "Test a project with a build tool execution") @@ -193,7 +200,7 @@ public void testTestProjectWithBuildTool() throws IOException { new CommandLine(testCommand).parseArgs(); testCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("test-project-with-build-tool.txt")); } @@ -208,7 +215,7 @@ public void testHeapDumpGenerationForOOM() { testCommand.execute(); } catch (BLauncherException e) { File projectDir = new File(projectPath.toString()); - FileFilter fileFilter = new WildcardFileFilter("java_pid*.hprof"); + FileFilter fileFilter = WildcardFileFilter.builder().setWildcards("java_pid*.hprof").get(); Assert.assertTrue(Objects.requireNonNull(projectDir.listFiles(fileFilter)).length > 0); } } @@ -218,33 +225,32 @@ public void testTestCommandPreservingBinJarInTargetDir() throws IOException { Path projectPath = this.testResources.resolve("validMultiModuleProjectWithTests"); System.setProperty(ProjectConstants.USER_DIR, projectPath.toString()); // build the project - BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, true , false); + BuildCommand buildCommand = new BuildCommand(projectPath, printStream, printStream, false , false); new CommandLine(buildCommand).parseArgs(); buildCommand.execute(); - Assert.assertTrue(projectPath.resolve("target").resolve("bin").resolve("winery.jar").toFile().exists()); - String md5BinJar = DigestUtils.md5Hex( - Files.newInputStream(projectPath.resolve("target").resolve("bin").resolve("winery.jar"))); + Assert.assertTrue(projectPath.resolve("target/bin/winery.jar").toFile().exists()); + String md5BinJar = DigestUtils.md5Hex(Files.newInputStream(projectPath.resolve("target/bin/winery.jar"))); // Run tests TestCommand testCommand = new TestCommand(projectPath, printStream, printStream, false); new CommandLine(testCommand).parseArgs(); testCommand.execute(); - Assert.assertTrue(projectPath.resolve("target").resolve("bin").resolve("winery.jar").toFile().exists()); + Assert.assertTrue(projectPath.resolve("target/bin/winery.jar").toFile().exists()); Assert.assertEquals(md5BinJar, DigestUtils.md5Hex( - Files.newInputStream(projectPath.resolve("target").resolve("bin").resolve("winery.jar")))); - Assert.assertTrue(projectPath.resolve("target").resolve("cache").resolve("foo") - .resolve("winery").resolve("0.1.0").resolve("java17") - .resolve("foo-winery-0.1.0.jar").toFile().exists()); - Assert.assertTrue(projectPath.resolve("target").resolve("cache").resolve("foo") - .resolve("winery").resolve("0.1.0").resolve("java17") - .resolve("foo-winery-0.1.0-testable.jar").toFile().exists()); + Files.newInputStream(projectPath.resolve("target/bin/winery.jar")))); + Assert.assertTrue(projectPath.resolve("target/cache/foo/winery/0.1.0/java17/foo-winery-0.1.0.jar") + .toFile().exists()); + Assert.assertTrue(projectPath.resolve("target/cache/foo/winery/0.1.0/java17/foo-winery-0.1.0-testable.jar") + .toFile().exists()); } - @Test(description = "Test a ballerina project with an invalid argument for --coverage-format") - public void testUnsupportedCoverageFormat() throws IOException { + @Test(description = "Test a ballerina project with an invalid argument for --coverage-format", + dataProvider = "optimizeDependencyCompilation") + public void testUnsupportedCoverageFormat(Boolean optimizeDependencyCompilation) throws IOException { Path projectPath = this.testResources.resolve("validProjectWithTests"); TestCommand testCommand = new TestCommand( - projectPath, printStream, printStream, false, false, true, "html"); + projectPath, printStream, printStream, false, false, true, "html", + optimizeDependencyCompilation); new CommandLine(testCommand).parseArgs(); testCommand.execute(); @@ -267,43 +273,44 @@ public void testCustomTargetDirWithTestCmd() { Assert.assertFalse(Files.exists(customTargetDir.resolve("bin"))); Assert.assertTrue(Files.exists(customTargetDir.resolve("cache"))); - Assert.assertTrue(Files.exists(customTargetDir.resolve("cache").resolve("tests_cache").resolve("test_suit" + - ".json"))); + Assert.assertTrue(Files.exists(customTargetDir.resolve("cache/tests_cache/test_suit.json"))); Assert.assertTrue(Files.exists(customTargetDir.resolve("build"))); Assert.assertTrue(Files.exists(customTargetDir.resolve("report"))); - Assert.assertTrue(Files.exists(customTargetDir.resolve("report").resolve("test_results.json"))); + Assert.assertTrue(Files.exists(customTargetDir.resolve("report/test_results.json"))); Assert.assertTrue(Files.exists(customTargetDir.resolve("rerun_test.json"))); - Assert.assertTrue(Files.exists(customTargetDir.resolve("cache").resolve("tests_cache").resolve("test_suit" + - ".json"))); + Assert.assertTrue(Files.exists(customTargetDir.resolve("cache/tests_cache/test_suit.json"))); } - @Test(description = "Test a ballerina project with --test-report") - public void testTestWithReport() { + @Test(description = "Test a ballerina project with --test-report", dataProvider = "optimizeDependencyCompilation") + public void testTestWithReport(Boolean optimizeDependencyCompilation) { Path projectPath = this.testResources.resolve("validProjectWithTests"); TestCommand testCommand = new TestCommand( - projectPath, printStream, printStream, false, true, false, null); + projectPath, printStream, printStream, false, true, false, null, optimizeDependencyCompilation); new CommandLine(testCommand).parseArgs(); try (MockedStatic testUtilsMockedStatic = Mockito.mockStatic( TestUtils.class, Mockito.CALLS_REAL_METHODS)) { testUtilsMockedStatic.when(TestUtils::getReportToolsPath) - .thenReturn(projectPath.resolve("resources").resolve("coverage").resolve("report.zip")); + .thenReturn(projectPath.resolve("resources/coverage/report.zip")); testCommand.execute(); } - Path reportDir = projectPath.resolve("target").resolve("report"); + Path reportDir = projectPath.resolve("target/report"); Assert.assertTrue(Files.exists(reportDir)); Assert.assertTrue(Files.exists(reportDir.resolve("favicon.ico"))); Assert.assertTrue(Files.exists(reportDir.resolve("index.html"))); Assert.assertTrue(Files.exists(reportDir.resolve("test_results.json"))); Assert.assertTrue(Files.exists(reportDir.resolve("manifest.json"))); - Assert.assertTrue(Files.exists(reportDir.resolve("static").resolve("css").resolve("2.d5162072.chunk.css"))); - Assert.assertTrue(Files.exists(reportDir.resolve("static").resolve("css").resolve("main.15691da7.chunk.css"))); - Assert.assertTrue(Files.exists(reportDir.resolve("static").resolve("js").resolve("2.bc541f30.chunk.js"))); - Assert.assertTrue(Files.exists(reportDir.resolve("static").resolve("js").resolve("main.ea323a3b.chunk.js"))); + Assert.assertTrue(Files.exists(reportDir.resolve("static/css/2.d5162072.chunk.css"))); + Assert.assertTrue(Files.exists(reportDir.resolve("static/css/main.15691da7.chunk.css"))); + Assert.assertTrue(Files.exists(reportDir.resolve("static/js/2.bc541f30.chunk.js"))); + Assert.assertTrue(Files.exists(reportDir.resolve("static/js/main.ea323a3b.chunk.js"))); } @Test(description = "tests bal test command with sticky flag") public void testBalTestWithStickyFlag() throws IOException { + if (isWindows()) { + throw new SkipException("Currently failing on Windows"); + } // Cache package pkg_a 1.0.0 Path balTestWithStickyFlagPath = testResources.resolve("balTestWithStickyFlag"); BCompileUtil.compileAndCacheBala(balTestWithStickyFlagPath.resolve("pkg_a_100"), @@ -317,7 +324,7 @@ public void testBalTestWithStickyFlag() throws IOException { new CommandLine(firstTestCommand).parseArgs(); firstTestCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("bal-test-project.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("bal-test-project.txt")); Assert.assertTrue(projectPath.resolve(DEPENDENCIES_TOML).toFile().exists()); Assert.assertEquals(readFileAsString(projectPath.resolve(DEPENDENCIES_TOML)).trim(), readFileAsString(projectPath.resolve(RESOURCE_DIR_NAME).resolve("expectedDeps.toml")) @@ -335,7 +342,7 @@ public void testBalTestWithStickyFlag() throws IOException { new CommandLine(secondTestCommand).parseArgs("--sticky"); secondTestCommand.execute(); String secondBuildLog = readOutput(true); - Assert.assertEquals(secondBuildLog.replaceAll("\r", ""), getOutput("bal-test-project.txt")); + Assert.assertEquals(secondBuildLog.replace("\r", ""), getOutput("bal-test-project.txt")); Assert.assertTrue(projectPath.resolve(DEPENDENCIES_TOML).toFile().exists()); Assert.assertEquals(readFileAsString(projectPath.resolve(DEPENDENCIES_TOML)).trim(), readFileAsString(projectPath.resolve(RESOURCE_DIR_NAME).resolve("expectedDeps.toml")) @@ -356,18 +363,20 @@ public void testTestBalProjectWithDumpGraphFlag() throws IOException { TestCommand testCommand = new TestCommand(projectPath, printStream, printStream, false); new CommandLine(testCommand).parseArgs("--dump-graph"); testCommand.execute(); - String buildLog = readOutput(true).replaceAll("\r", "").strip(); + String buildLog = readOutput(true).replace("\r", "").strip(); Assert.assertEquals(buildLog, getOutput("test-project-with-dump-graph.txt")); - Assert.assertTrue(projectPath.resolve("target").resolve("cache").resolve("foo") - .resolve("package_a").resolve("0.1.0").resolve("java17") - .resolve("foo-package_a-0.1.0.jar").toFile().exists()); + Assert.assertTrue(projectPath.resolve("target/cache/foo/package_a/0.1.0/java17/foo-package_a-0.1.0.jar") + .toFile().exists()); ProjectUtils.deleteDirectory(projectPath.resolve("target")); } @Test(description = "Test a ballerina project with the flag dump-raw-graphs") public void testTestBalProjectWithDumpRawGraphsFlag() throws IOException { + if (isWindows()) { + throw new SkipException("Currently failing on Windows"); + } Path dumpGraphResourcePath = this.testResources.resolve("projectsForDumpGraph"); BCompileUtil.compileAndCacheBala(dumpGraphResourcePath.resolve("package_c"), testDistCacheDirectory, projectEnvironmentBuilder); @@ -380,12 +389,11 @@ public void testTestBalProjectWithDumpRawGraphsFlag() throws IOException { TestCommand testCommand = new TestCommand(projectPath, printStream, printStream, false); new CommandLine(testCommand).parseArgs("--dump-raw-graphs"); testCommand.execute(); - String buildLog = readOutput(true).replaceAll("\r", "").strip(); + String buildLog = readOutput(true).replace("\r", "").replace("\\", "/").strip(); Assert.assertEquals(buildLog, getOutput("test-project-with-dump-raw-graphs.txt")); - Assert.assertTrue(projectPath.resolve("target").resolve("cache").resolve("foo") - .resolve("package_a").resolve("0.1.0").resolve("java17") - .resolve("foo-package_a-0.1.0.jar").toFile().exists()); + Assert.assertTrue(projectPath.resolve("target/cache/foo/package_a/0.1.0/java17/foo-package_a-0.1.0.jar") + .toFile().exists()); ProjectUtils.deleteDirectory(projectPath.resolve("target")); } @@ -397,16 +405,272 @@ public void testTestEmptyPackage() throws IOException { TestCommand testCommand = new TestCommand(projectPath, printStream, printStream, false); new CommandLine(testCommand).parseArgs(); - testCommand.execute(); + try { + testCommand.execute(); + } catch (BLauncherException e) { + List messages = e.getMessages(); + Assert.assertEquals(messages.size(), 1); + Assert.assertEquals(messages.get(0), getOutput("build-empty-package.txt")); + } + } + @Test(description = "Test an empty project with build tools") + public void testTestEmptyProjectWithBuildTools() throws IOException { + BCompileUtil.compileAndCacheBala( + testResources.resolve("buildToolResources/tools/ballerina-generate-file").toString(), + testDistCacheDirectory, projectEnvironmentBuilder); + Path projectPath = this.testResources.resolve("emptyProjectWithBuildTool"); + replaceDependenciesTomlContent(projectPath, "**INSERT_DISTRIBUTION_VERSION_HERE**", + RepoUtils.getBallerinaShortVersion()); + System.setProperty("user.dir", projectPath.toString()); + try (MockedStatic repoUtils = Mockito.mockStatic( + BuildToolUtils.class, Mockito.CALLS_REAL_METHODS)) { + repoUtils.when(BuildToolUtils::getCentralBalaDirPath).thenReturn(testDistCacheDirectory.resolve("bala")); + TestCommand testCommand = new TestCommand(projectPath, printStream, printStream, false); + new CommandLine(testCommand).parseArgs(); + testCommand.execute(); + } String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("build-empty-package.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("test-empty-project-with-build-tools.txt")); + } + + @Test(description = "Test the emission of testable fat jar for a project with tests") + public void testTestableFatJarEmission() { + Path projectPath = this.testResources.resolve("validProjectWithTests"); + System.setProperty(ProjectConstants.USER_DIR, projectPath.toString()); + + Path mockedLocalRepo = this.testResources.resolve("mocked-local-repo"); + System.setProperty("user.home", mockedLocalRepo.toString()); + + TestCommand testCommand = new TestCommand(projectPath, printStream, printStream, false); + new CommandLine(testCommand).parseArgs("--cloud=docker"); + testCommand.execute(); + Path targetDir = projectPath.resolve("target"); + Path testableJar = targetDir.resolve("bin/tests/winery-testable.jar"); + Assert.assertTrue(Files.exists(testableJar)); + Path mainArgsFile = testableJar.getParent().resolve(TEST_RUNTIME_MAIN_ARGS_FILE); + Assert.assertTrue(Files.exists(mainArgsFile)); + } + + @Test(description = "Test the correct execution of the generated testable fat jar", + dependsOnMethods = "testTestableFatJarEmission") + public void testTestableFatJarExecution() throws IOException { + if (isWindows()) { + throw new SkipException("Currently failing on Windows"); + } + Path projectPath = this.testResources.resolve("validProjectWithTests"); + Path testableJar = projectPath.resolve("target/bin/tests/winery-testable.jar"); + Path mainArgsFile = testableJar.getParent().resolve(TEST_RUNTIME_MAIN_ARGS_FILE); + + // Read the main args from the file (line separated) + List mainArgs = Files.readAllLines(mainArgsFile); + mainArgs.set(TesterinaConstants.RunTimeArgs.IS_FAT_JAR_EXECUTION, "true"); + mainArgs.set(TesterinaConstants.RunTimeArgs.TEST_SUITE_JSON_PATH, TestUtils.getJsonFilePathInFatJar("/")); + mainArgs.set(TesterinaConstants.RunTimeArgs.TARGET_DIR, projectPath.resolve("target").toString()); + + List pbArgs = new ArrayList<>(TestUtils.getInitialCmdArgs(null, null)); + pbArgs.add("-jar"); + pbArgs.add(testableJar.toString()); + pbArgs.addAll(mainArgs); + + ProcessBuilder processBuilder = new ProcessBuilder(pbArgs).redirectErrorStream(true); + Process process = processBuilder.start(); + StringBuilder output = new StringBuilder(); + int exitCode = -1; + try { + try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + br.lines().forEach(line -> output.append(line).append("\n")); + } + exitCode = process.waitFor(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + Assert.assertEquals(exitCode, 0); + Assert.assertTrue(output.toString().contains("[pass] testRunMain")); + } + + @Test(description = "Test the emission of testable fat jar for a project with mocks") + public void testEmissionOfTestableFatJarForProjectWithMocking() throws IOException { + Path projectPath = this.testResources.resolve("projectWithMocks"); + System.setProperty(ProjectConstants.USER_DIR, projectPath.toString()); + + Path mockedLocalRepo = this.testResources.resolve("mocked-local-repo"); + System.setProperty("user.home", mockedLocalRepo.toString()); + + TestCommand testCommand = new TestCommand(projectPath, printStream, printStream, false); + new CommandLine(testCommand).parseArgs("--cloud=docker"); + testCommand.execute(); + Path targetDir = projectPath.resolve("target"); + Path testableJar = targetDir.resolve("bin/tests/projectWithMocks-testable.jar"); + Assert.assertTrue(Files.exists(testableJar)); + Path mainArgsFile = testableJar.getParent().resolve(TEST_RUNTIME_MAIN_ARGS_FILE); + Assert.assertTrue(Files.exists(mainArgsFile)); + //should exist only one testable jar + try (Stream testableJars = Files.list(testableJar.getParent())) { + Assert.assertEquals(testableJars.filter(path -> path.toString().endsWith(".jar")) + .map(Path::toFile).toList().size(), 1); + } + } + + @Test(description = "Test the execution of testable fat jar for a project with tests and mocks", + dependsOnMethods = "testEmissionOfTestableFatJarForProjectWithMocking") + public void testExecutionOfTestableFatJarForProjectWithMocking() throws IOException { + if (isWindows()) { + throw new SkipException("Currently failing on Windows"); + } + Path projectPath = this.testResources.resolve("projectWithMocks"); + Path testableJar = projectPath.resolve("target/bin/tests/projectWithMocks-testable.jar"); + Path mainArgsFile = testableJar.getParent().resolve(TEST_RUNTIME_MAIN_ARGS_FILE); + + // Read the main args from the file (line separated) + List mainArgs = Files.readAllLines(mainArgsFile); + mainArgs.set(TesterinaConstants.RunTimeArgs.IS_FAT_JAR_EXECUTION, "true"); + mainArgs.set(TesterinaConstants.RunTimeArgs.TEST_SUITE_JSON_PATH, TestUtils.getJsonFilePathInFatJar("/")); + mainArgs.set(TesterinaConstants.RunTimeArgs.TARGET_DIR, projectPath.resolve("target").toString()); + + List pbArgs = new ArrayList<>(TestUtils.getInitialCmdArgs(null, null)); + pbArgs.add("-jar"); + pbArgs.add(testableJar.toString()); + pbArgs.addAll(mainArgs); + + ProcessBuilder processBuilder = new ProcessBuilder(pbArgs).redirectErrorStream(true); + Process process = processBuilder.start(); + StringBuilder output = new StringBuilder(); + int exitCode = -1; + try { + try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + br.lines().forEach(line -> output.append(line).append("\n")); + } + exitCode = process.waitFor(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + Assert.assertEquals(exitCode, 0); + Assert.assertTrue(output.toString().contains("[pass] testMockedIntSub")); + Assert.assertTrue(output.toString().contains("[pass] testMockedIntAdd")); + Assert.assertTrue(output.toString().contains("[pass] testRealIntSub")); + } + + @Test(description = "Test the emission of a single fat jar when both cloud and graalvm flags are enabled") + public void testEmissionOfSingleFatJarForCloudAndGraalVM() throws IOException { + Path projectPath = this.testResources.resolve("validProjectWithTests"); + System.setProperty(ProjectConstants.USER_DIR, projectPath.toString()); + + Path mockedLocalRepo = this.testResources.resolve("mocked-local-repo"); + System.setProperty("user.home", mockedLocalRepo.toString()); + + TestCommand testCommand = new TestCommand(projectPath, printStream, printStream, false); + new CommandLine(testCommand).parseArgs("--cloud=docker", "--graalvm"); + testCommand.execute(); + Path targetDir = projectPath.resolve("target"); + Path testableJar = targetDir.resolve("bin/tests/winery-testable.jar"); + Assert.assertTrue(Files.exists(testableJar)); + Path mainArgsFile = testableJar.getParent().resolve(TEST_RUNTIME_MAIN_ARGS_FILE); + Assert.assertTrue(Files.exists(mainArgsFile)); + //should exist only one testable jar + try (Stream testableJars = Files.list(testableJar.getParent())) { + Assert.assertEquals(testableJars.filter(path -> path.toString().endsWith(".jar")) + .map(Path::toFile).toList().size(), 1); + } + } + + @Test(description = "Test the emission of multiple testable fat jars for a project with mocks when " + + "both cloud and graalvm flags are enabled", priority = 1) + public void testEmissionOfMultipleFatJarsForProjectWithMockingForCloudAndGraalVM() throws IOException { + Path projectPath = this.testResources.resolve("projectWithMocks"); + System.setProperty(ProjectConstants.USER_DIR, projectPath.toString()); + + Path mockedLocalRepo = this.testResources.resolve("mocked-local-repo"); + System.setProperty("user.home", mockedLocalRepo.toString()); + + TestCommand testCommand = new TestCommand(projectPath, printStream, printStream, false); + new CommandLine(testCommand).parseArgs("--cloud=docker", "--graalvm"); + testCommand.execute(); + Path targetDir = projectPath.resolve("target"); + Path mainArgsFile = targetDir.resolve("bin/tests").resolve(TEST_RUNTIME_MAIN_ARGS_FILE); + Assert.assertTrue(Files.exists(mainArgsFile)); + //should exist only one testable jar + try (Stream files = Files.list(mainArgsFile.getParent())) { + List testableJars = files.filter(path -> path.toString().endsWith(".jar")) + .map(Path::toFile).toList(); + Assert.assertEquals(testableJars.size(), 2); //2 because default module and 1 sub module + List jarFileNames = Arrays.asList("projectWithMocks-testable.jar", + "projectWithMocks.mod1-testable.jar"); + for (File testableJar : testableJars) { + Assert.assertTrue(jarFileNames.contains(testableJar.getName())); + } + } + } + + @Test(description = "Test the execution of multiple testable fat jars for a project with tests and mocks", + dependsOnMethods = "testEmissionOfMultipleFatJarsForProjectWithMockingForCloudAndGraalVM", priority = 1) + public void testExecutionOfMultipleTestableFatJarsForProjectWithTestsAndMocks() throws IOException { + if (isWindows()) { + throw new SkipException("Currently failing on Windows"); + } + Path projectPath = this.testResources.resolve("projectWithMocks"); + Path mainArgsFile = projectPath.resolve("target/bin/tests").resolve(TEST_RUNTIME_MAIN_ARGS_FILE); + + // Read the main args from the file (line separated) + List mainArgs = Files.readAllLines(mainArgsFile); + mainArgs.set(TesterinaConstants.RunTimeArgs.IS_FAT_JAR_EXECUTION, "true"); + mainArgs.set(TesterinaConstants.RunTimeArgs.TEST_SUITE_JSON_PATH, TestUtils.getJsonFilePathInFatJar("/")); + mainArgs.set(TesterinaConstants.RunTimeArgs.TARGET_DIR, projectPath.resolve("target").toString()); + + try (Stream files = Files.list(mainArgsFile.getParent())) { + List testableJars = files.filter(path -> path.toString().endsWith(".jar")).toList(); + for (Path testableJar : testableJars) { + List pbArgs = new ArrayList<>(TestUtils.getInitialCmdArgs(null, null)); + pbArgs.add("-jar"); + pbArgs.add(testableJar.toString()); + pbArgs.addAll(mainArgs); + + ProcessBuilder processBuilder = new ProcessBuilder(pbArgs).redirectErrorStream(true); + Process process = processBuilder.start(); + StringBuilder output = new StringBuilder(); + int exitCode = -1; + try { + try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + br.lines().forEach(line -> output.append(line).append("\n")); + } + exitCode = process.waitFor(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + Assert.assertEquals(exitCode, 0); + if (testableJar.getFileName().toString().equals("projectWithMocks-testable.jar")) { + Assert.assertTrue(output.toString().contains("[pass] testMockedIntAdd")); + Assert.assertTrue(output.toString().contains("[pass] testRealIntSub")); + } else { + Assert.assertTrue(output.toString().contains("[pass] testMockedIntSub")); + } + } + } + } + + @Test(description = "Test the emission of testable fat jar for a single test bal file") + public void testEmissionOfTestableFatJarForSingleTestBalFile() { + Path projectPath = this.testResources.resolve("validProjectWithTests") + .resolve("tests"); + System.setProperty(ProjectConstants.USER_DIR, projectPath.toString()); + + Path mockedLocalRepo = this.testResources.resolve("mocked-local-repo"); + System.setProperty("user.home", mockedLocalRepo.toString()); + + TestCommand testCommand = new TestCommand(projectPath, printStream, printStream, false); + new CommandLine(testCommand).parseArgs("--cloud=docker", "main_tests.bal"); + testCommand.execute(); + Path targetDir = projectPath.resolve("target"); + Path testableJar = targetDir.resolve("bin/tests/winery-testable.jar"); + Assert.assertFalse(Files.exists(testableJar)); //should not exist + Path mainArgsFile = testableJar.getParent().resolve(TEST_RUNTIME_MAIN_ARGS_FILE); + Assert.assertFalse(Files.exists(mainArgsFile)); //should not exist } static class Copy extends SimpleFileVisitor { - private Path fromPath; - private Path toPath; - private StandardCopyOption copyOption; + private final Path fromPath; + private final Path toPath; + private final StandardCopyOption copyOption; public Copy(Path fromPath, Path toPath, StandardCopyOption copyOption) { this.fromPath = fromPath; diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/TestNativeImageCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/TestNativeImageCommandTest.java index 5f924f0bc969..af8bb297e067 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/TestNativeImageCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/TestNativeImageCommandTest.java @@ -6,6 +6,7 @@ import io.ballerina.projects.environment.EnvironmentBuilder; import io.ballerina.projects.util.ProjectConstants; import org.testng.Assert; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import picocli.CommandLine; @@ -15,10 +16,8 @@ import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Objects; - import static io.ballerina.projects.util.ProjectConstants.DIST_CACHE_DIRECTORY; /** @@ -30,20 +29,25 @@ public class TestNativeImageCommandTest extends BaseCommandTest { private Path testResources; private Path testDistCacheDirectory; ProjectEnvironmentBuilder projectEnvironmentBuilder; + private static final Path LOG_FILE = Path.of("build/logs/log_creator_combined_plugin/compiler-plugin.txt") + .toAbsolutePath(); + @Override @BeforeClass public void setup() throws IOException { super.setup(); + Files.createDirectories(LOG_FILE.getParent()); + Files.writeString(LOG_FILE, ""); try { this.testResources = super.tmpDir.resolve("test-cmd-test-resources"); - Path testBuildDirectory = Paths.get("build").toAbsolutePath(); + Path testBuildDirectory = Path.of("build").toAbsolutePath(); this.testDistCacheDirectory = testBuildDirectory.resolve(DIST_CACHE_DIRECTORY); - Path customUserHome = Paths.get("build", "user-home"); + Path customUserHome = Path.of("build/user-home"); Environment environment = EnvironmentBuilder.getBuilder().setUserHome(customUserHome).build(); projectEnvironmentBuilder = ProjectEnvironmentBuilder.getBuilder(environment); URI testResourcesURI = Objects.requireNonNull( getClass().getClassLoader().getResource("test-resources")).toURI(); - Files.walkFileTree(Paths.get(testResourcesURI), new TestCommandTest.Copy(Paths.get(testResourcesURI), + Files.walkFileTree(Path.of(testResourcesURI), new TestCommandTest.Copy(Path.of(testResourcesURI), this.testResources)); } catch (URISyntaxException e) { Assert.fail("error loading resources"); @@ -55,7 +59,7 @@ public void testNativeImageTests() throws IOException { Path projectPath = this.testResources.resolve("validProjectWithTests"); System.setProperty(ProjectConstants.USER_DIR, projectPath.toString()); TestCommand testCommand = new TestCommand(projectPath, printStream, printStream, false, true, ""); - new CommandLine(testCommand).parse(); + new CommandLine(testCommand).parseArgs(); testCommand.execute(); String buildLog = readOutput(true); Assert.assertTrue(buildLog.contains("1 passing")); @@ -66,20 +70,31 @@ public void testNativeImageTestsWithAdditionalArgs() throws IOException { Path projectPath = this.testResources.resolve("validProjectWithTests"); System.setProperty(ProjectConstants.USER_DIR, projectPath.toString()); TestCommand testCommand = new TestCommand(projectPath, printStream, printStream, false, true, "-H:Name=foo"); - new CommandLine(testCommand).parse(); - testCommand.execute(); + new CommandLine(testCommand).parseArgs(); + try { + testCommand.execute(); + } catch (BLauncherException e) { + readOutput(false); + Assert.fail(e.getDetailedMessages().get(0)); + } String buildLog = readOutput(true); - Assert.assertTrue(buildLog.contains("Generating 'foo' (executable)")); + Assert.assertTrue(buildLog.contains("Generating 'winery' (executable)"), buildLog); } - @Test(description = "Test function mocking") + //TODO: Fix this testcase (#42937) + @Test(description = "Test function mocking", enabled = false) public void testNativeFunctionMockTests() throws IOException { Path projectPath = this.testResources.resolve("mockFunctionNative"); System.setProperty(ProjectConstants.USER_DIR, projectPath.toString()); TestCommand testCommand = new TestCommand(projectPath, printStream, printStream, false, true, ""); // non existing bal file - new CommandLine(testCommand).parse(); - testCommand.execute(); + new CommandLine(testCommand).parseArgs(); + try { + testCommand.execute(); + } catch (BLauncherException e) { + String output = readOutput(true); + Assert.fail(e + "\n" + e.getDetailedMessages().toString() + "\n" + output); + } String buildLog = readOutput(true); Assert.assertTrue(buildLog.contains("[pass] intAddTest")); Assert.assertTrue(buildLog.contains("[pass] intAddTest2")); @@ -92,8 +107,8 @@ public void testNativeFunctionMockTests() throws IOException { //TODO: Change the output once the resource generation plugin is disabled @Test(description = "Test a valid ballerina file") - public void testTestBalFile() throws IOException { - Path validBalFilePath = this.testResources.resolve("valid-test-bal-file").resolve("sample_tests.bal"); + public void testTestBalFile() { + Path validBalFilePath = this.testResources.resolve("valid-test-bal-file/sample_tests.bal"); System.setProperty(ProjectConstants.USER_DIR, this.testResources.resolve("valid-test-bal-file").toString()); TestCommand testCommand = new TestCommand(validBalFilePath, printStream, printStream, false, true, ""); new CommandLine(testCommand).parseArgs(validBalFilePath.toString()); @@ -101,14 +116,14 @@ public void testTestBalFile() throws IOException { testCommand.execute(); } catch (BLauncherException e) { Assert.assertTrue(e.getDetailedMessages().get(0).contains("native image testing is not supported for " + - "standalone Ballerina files containing resources")); + "standalone Ballerina files containing resources"), e.getDetailedMessages().get(0)); } } //TODO: Change the output once the resource generation plugin is disabled @Test(description = "Test a valid ballerina file with additional args") - public void testTestBalFileWithAdditionalArgs() throws IOException { - Path validBalFilePath = this.testResources.resolve("valid-test-bal-file").resolve("sample_tests.bal"); + public void testTestBalFileWithAdditionalArgs() { + Path validBalFilePath = this.testResources.resolve("valid-test-bal-file/sample_tests.bal"); System.setProperty(ProjectConstants.USER_DIR, this.testResources.resolve("valid-test-bal-file").toString()); TestCommand testCommand = new TestCommand(validBalFilePath, printStream, printStream, false, true, "-H:Name=foo"); @@ -117,14 +132,14 @@ public void testTestBalFileWithAdditionalArgs() throws IOException { testCommand.execute(); } catch (BLauncherException e) { Assert.assertTrue(e.getDetailedMessages().get(0).contains("native image testing is not supported for " + - "standalone Ballerina files containing resources")); + "standalone Ballerina files containing resources"), e.getDetailedMessages().get(0)); } } //TODO: Change the output once the resource generation plugin is disabled @Test(description = "Test a valid ballerina file with periods in the file name") - public void testTestBalFileWithPeriods() throws IOException { - Path validBalFilePath = this.testResources.resolve("valid-test-bal-file").resolve("sample.tests.bal"); + public void testTestBalFileWithPeriods() { + Path validBalFilePath = this.testResources.resolve("valid-test-bal-file/sample.tests.bal"); System.setProperty(ProjectConstants.USER_DIR, this.testResources.resolve("valid-test-bal-file").toString()); TestCommand testCommand = new TestCommand(validBalFilePath, printStream, printStream, @@ -134,7 +149,14 @@ public void testTestBalFileWithPeriods() throws IOException { testCommand.execute(); } catch (BLauncherException e) { Assert.assertTrue(e.getDetailedMessages().get(0).contains("native image testing is not supported for " + - "standalone Ballerina files containing resources")); + "standalone Ballerina files containing resources"), e.getDetailedMessages().get(0)); } } + + @AfterClass + public void cleanUp() throws IOException { + Files.deleteIfExists(LOG_FILE); + Files.deleteIfExists(LOG_FILE.getParent()); + Files.deleteIfExists(LOG_FILE.getParent().getParent()); + } } diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/ToolCommandTest.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/ToolCommandTest.java index cc57ff9fdc56..27f96ed6274c 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/ToolCommandTest.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/cmd/ToolCommandTest.java @@ -36,7 +36,6 @@ import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Objects; import java.util.Optional; @@ -51,6 +50,7 @@ public class ToolCommandTest extends BaseCommandTest { private Path testResources; + @Override @BeforeClass public void setup() throws IOException { super.setup(); @@ -58,8 +58,8 @@ public void setup() throws IOException { this.testResources = super.tmpDir.resolve("build-test-resources"); URI testResourcesURI = Objects.requireNonNull(getClass().getClassLoader().getResource("test-resources")) .toURI(); - Files.walkFileTree(Paths.get(testResourcesURI), - new BuildCommandTest.Copy(Paths.get(testResourcesURI), this.testResources)); + Files.walkFileTree(Path.of(testResourcesURI), + new BuildCommandTest.Copy(Path.of(testResourcesURI), this.testResources)); } catch (URISyntaxException e) { Assert.fail("error loading resources"); } @@ -79,7 +79,7 @@ public void testPullToolFromLocal() throws IOException { } String buildLog = readOutput(true); - Assert.assertEquals(buildLog, "tool 'luhee:1.1.0' successfully set as the active version.\n"); + Assert.assertEquals(buildLog.replace("\r", ""), "tool 'luhee:1.1.0' successfully set as the active version.\n"); Assert.assertTrue(Files.exists(mockHomeRepo.resolve(".config").resolve("bal-tools.toml"))); BalToolsToml balToolsToml = BalToolsToml.from(mockHomeRepo.resolve(".config").resolve("bal-tools.toml")); BalToolsManifest balToolsManifest = BalToolsManifestBuilder.from(balToolsToml).build(); @@ -106,7 +106,8 @@ public void testUseToolFromLocal() throws IOException { toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertTrue(buildLog.contains("tool 'luhee:1.2.0' successfully set as the active version.\n")); + Assert.assertTrue(buildLog.replace("\r", "") + .contains("tool 'luhee:1.2.0' successfully set as the active version.\n"), buildLog); Assert.assertTrue(Files.exists(mockHomeRepo.resolve(".config").resolve("bal-tools.toml"))); BalToolsToml balToolsToml = BalToolsToml.from(mockHomeRepo.resolve(".config").resolve("bal-tools.toml")); BalToolsManifest balToolsManifest = BalToolsManifestBuilder.from(balToolsToml).build(); @@ -121,7 +122,8 @@ public void testUseToolFromLocal() throws IOException { new CommandLine(toolCommand).parseArgs("use", "luhee:1.1.0", "--repository=local"); toolCommand.execute(); buildLog = readOutput(true); - Assert.assertTrue(buildLog.contains("tool 'luhee:1.1.0' successfully set as the active version.\n")); + Assert.assertTrue(buildLog.replace("\r", "") + .contains("tool 'luhee:1.1.0' successfully set as the active version.\n")); balToolsToml = BalToolsToml.from(mockHomeRepo.resolve(".config").resolve("bal-tools.toml")); balToolsManifest = BalToolsManifestBuilder.from(balToolsToml).build(); tool = balToolsManifest.getActiveTool("luhee"); @@ -148,7 +150,8 @@ public void testRemoveToolFromLocal() throws IOException { toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertTrue(buildLog.contains("tool 'luhee:1.2.0' successfully set as the active version.\n")); + Assert.assertTrue(buildLog.replace("\r", "") + .contains("tool 'luhee:1.2.0' successfully set as the active version.\n"), buildLog); Assert.assertTrue(Files.exists(mockHomeRepo.resolve(".config").resolve("bal-tools.toml"))); BalToolsToml balToolsToml = BalToolsToml.from(mockHomeRepo.resolve(".config") .resolve("bal-tools.toml")); @@ -164,7 +167,8 @@ public void testRemoveToolFromLocal() throws IOException { new CommandLine(toolCommand).parseArgs("use", "luhee:1.1.0", "--repository=local"); toolCommand.execute(); buildLog = readOutput(true); - Assert.assertTrue(buildLog.contains("tool 'luhee:1.1.0' successfully set as the active version.\n")); + Assert.assertTrue(buildLog.replace("\r", "") + .contains("tool 'luhee:1.1.0' successfully set as the active version.\n")); balToolsToml = BalToolsToml.from(mockHomeRepo.resolve(".config").resolve("bal-tools.toml")); balToolsManifest = BalToolsManifestBuilder.from(balToolsToml).build(); tool = balToolsManifest.getActiveTool("luhee"); @@ -178,7 +182,8 @@ public void testRemoveToolFromLocal() throws IOException { new CommandLine(toolCommand).parseArgs("remove", "luhee:1.2.0", "--repository=local"); toolCommand.execute(); buildLog = readOutput(true); - Assert.assertTrue(buildLog.contains("tool 'luhee:1.2.0' successfully removed.\n")); + Assert.assertTrue(buildLog.replace("\r", "") + .contains("tool 'luhee:1.2.0' successfully removed.\n")); balToolsToml = BalToolsToml.from(mockHomeRepo.resolve(".config").resolve("bal-tools.toml")); balToolsManifest = BalToolsManifestBuilder.from(balToolsToml).build(); tool = balToolsManifest.getTool("luhee", "1.2.0", "local"); @@ -194,13 +199,13 @@ public void testToolCommandWithHelpFlag() throws IOException { new CommandLine(toolCommand).parseArgs("--help"); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), expected); + Assert.assertEquals(buildLog.replace("\r", ""), expected); toolCommand = new ToolCommand(printStream, printStream, false); new CommandLine(toolCommand).parseArgs("-h"); toolCommand.execute(); buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), expected); + Assert.assertEquals(buildLog.replace("\r", ""), expected); } @Test(description = "Test tool command with no arguments") @@ -209,7 +214,7 @@ public void testToolCommandWithNoArgs() throws IOException { new CommandLine(toolCommand).parseArgs(); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-with-no-args.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-with-no-args.txt")); } @Test(description = "Test tool command with invalid sub command") @@ -218,7 +223,7 @@ public void testToolCommandWithInvalidSubCommand() throws IOException { new CommandLine(toolCommand).parseArgs("invalid-cmd"); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-with-invalid-sub-command.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-with-invalid-sub-command.txt")); } @Test(description = "Test tool pull sub-command with no arguments") @@ -227,7 +232,7 @@ public void testToolPullSubCommandWithNoArgs() throws IOException { new CommandLine(toolCommand).parseArgs("pull"); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-pull-with-no-args.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-pull-with-no-args.txt")); } @Test(description = "Test tool pull sub-command with too many arguments") @@ -236,7 +241,7 @@ public void testToolPullSubCommandWithTooManyArgs() throws IOException { new CommandLine(toolCommand).parseArgs("pull", "arg1", "arg2"); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-pull-with-too-many-args.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-pull-with-too-many-args.txt")); } @Test(description = "Test tool pull sub-command with invalid argument format") @@ -245,7 +250,7 @@ public void testToolPullSubCommandWithInvalidArgFormat() throws IOException { new CommandLine(toolCommand).parseArgs("pull", "id:1.0.1:extra"); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-pull-with-invalid-tool-id.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-pull-with-invalid-tool-id.txt")); } @Test(dataProvider = "invalidToolIds", description = "Test tool pull sub-command with invalid argument format") @@ -254,7 +259,7 @@ public void testToolPullSubCommandWithInvalidToolId(String toolId) throws IOExce new CommandLine(toolCommand).parseArgs("pull", toolId); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-pull-with-invalid-tool-id.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-pull-with-invalid-tool-id.txt")); } @Test(description = "Test tool pull sub-command with invalid tool version") @@ -263,7 +268,7 @@ public void testToolPullSubCommandWithInvalidToolVersion() throws IOException { new CommandLine(toolCommand).parseArgs("pull", "tool_id:1.1"); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-pull-with-invalid-tool-version.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-pull-with-invalid-tool-version.txt")); } @Test(description = "Test tool list sub-command with arguments") @@ -272,13 +277,13 @@ public void testToolListSubCommandWithArgs() throws IOException { new CommandLine(toolCommand).parseArgs("list", "arg"); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-list-with-args.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-list-with-args.txt")); toolCommand = new ToolCommand(printStream, printStream, false); new CommandLine(toolCommand).parseArgs("list", "arg1", "arg2"); toolCommand.execute(); buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-list-with-args.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-list-with-args.txt")); } @Test(description = "Test tool remove with more than one argument") @@ -287,7 +292,7 @@ public void testToolRemoveSubCommandWithTooManyArgs() throws IOException { new CommandLine(toolCommand).parseArgs("remove", "arg1", "arg2"); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-remove-with-too-many-args.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-remove-with-too-many-args.txt")); } @Test(description = "Test tool remove with more than no arguments") @@ -296,7 +301,7 @@ public void testToolRemoveSubCommandWithNoArgs() throws IOException { new CommandLine(toolCommand).parseArgs("remove"); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-remove-with-no-args.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-remove-with-no-args.txt")); } @Test(description = "Test tool remove sub-command with invalid argument format") @@ -305,7 +310,7 @@ public void testToolRemoveSubCommandWithInvalidArgFormat() throws IOException { new CommandLine(toolCommand).parseArgs("remove", "id:1.0.1:extra"); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-remove-with-invalid-tool-id.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-remove-with-invalid-tool-id.txt")); } @Test(dataProvider = "invalidToolIds", description = "Test tool remove sub-command with invalid argument format") @@ -314,7 +319,7 @@ public void testToolRemoveSubCommandWithInvalidToolId(String toolId) throws IOEx new CommandLine(toolCommand).parseArgs("remove", toolId); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-remove-with-invalid-tool-id.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-remove-with-invalid-tool-id.txt")); } @Test(description = "Test tool pull sub-command with invalid tool version") @@ -323,7 +328,7 @@ public void testToolRemoveSubCommandWithInvalidToolVersion() throws IOException new CommandLine(toolCommand).parseArgs("remove", "tool_id:1.1"); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-remove-with-invalid-tool-version.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-remove-with-invalid-tool-version.txt")); } @Test(description = "Test tool search with more than one argument") @@ -332,7 +337,7 @@ public void testToolSearchSubCommandWithTooManyArgs() throws IOException { new CommandLine(toolCommand).parseArgs("search", "arg1", "arg2"); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-search-with-too-many-args.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-search-with-too-many-args.txt")); } @Test(description = "Test tool search with more than no arguments") @@ -341,7 +346,7 @@ public void testToolSearchSubCommandWithNoArgs() throws IOException { new CommandLine(toolCommand).parseArgs("search"); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-search-with-no-args.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-search-with-no-args.txt")); } @Test(description = "Test tool use with more than one argument") @@ -350,7 +355,7 @@ public void testToolUseSubCommandWithTooManyArgs() throws IOException { new CommandLine(toolCommand).parseArgs("use", "arg1", "arg2"); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-use-with-too-many-args.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-use-with-too-many-args.txt")); } @Test(description = "Test tool use with more than no arguments") @@ -359,7 +364,7 @@ public void testToolUseSubCommandWithNoArgs() throws IOException { new CommandLine(toolCommand).parseArgs("use"); toolCommand.execute(); String buildLog = readOutput(true); - Assert.assertEquals(buildLog.replaceAll("\r", ""), getOutput("tool-use-with-no-args.txt")); + Assert.assertEquals(buildLog.replace("\r", ""), getOutput("tool-use-with-no-args.txt")); } @Test(description = "Test tool use sub-command with invalid argument format") diff --git a/cli/ballerina-cli/src/test/java/io/ballerina/cli/utils/TestCentralUtils.java b/cli/ballerina-cli/src/test/java/io/ballerina/cli/utils/TestCentralUtils.java index 46ca64ed95e6..364bcdd1e204 100644 --- a/cli/ballerina-cli/src/test/java/io/ballerina/cli/utils/TestCentralUtils.java +++ b/cli/ballerina-cli/src/test/java/io/ballerina/cli/utils/TestCentralUtils.java @@ -1,7 +1,6 @@ package io.ballerina.cli.utils; import io.ballerina.projects.Settings; -import org.ballerinalang.toml.exceptions.SettingsTomlException; import org.mockito.MockedStatic; import org.mockito.Mockito; import org.testng.Assert; @@ -9,7 +8,6 @@ import org.wso2.ballerinalang.util.RepoUtils; import java.nio.file.Path; -import java.nio.file.Paths; import static io.ballerina.projects.util.ProjectUtils.getAccessTokenOfCLI; @@ -18,10 +16,10 @@ */ public class TestCentralUtils { - private static final Path UTILS_TEST_RESOURCES = Paths.get("src/test/resources/test-resources/central-utils"); + private static final Path UTILS_TEST_RESOURCES = Path.of("src/test/resources/test-resources/central-utils"); @Test(description = "Test get access token from Settings.toml") - public void testGetAccessTokenOfCliFromSettings() throws SettingsTomlException { + public void testGetAccessTokenOfCliFromSettings() { try (MockedStatic repoUtils = Mockito.mockStatic(RepoUtils.class)) { repoUtils.when(RepoUtils::createAndGetHomeReposPath).thenReturn(UTILS_TEST_RESOURCES); Settings settings = RepoUtils.readSettings(); @@ -30,7 +28,7 @@ public void testGetAccessTokenOfCliFromSettings() throws SettingsTomlException { } @Test(description = "Test read settings") - public void testReadSettings() throws SettingsTomlException { + public void testReadSettings() { try (MockedStatic repoUtils = Mockito.mockStatic(RepoUtils.class)) { repoUtils.when(RepoUtils::createAndGetHomeReposPath).thenReturn(UTILS_TEST_RESOURCES); Settings settings = RepoUtils.readSettings(); diff --git a/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/dummy-tool-pkg/resources/sample-dummy-build-tool-1.4.0.jar b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/dummy-tool-pkg/resources/sample-dummy-build-tool-1.4.0.jar new file mode 100644 index 000000000000..a933078f43e8 Binary files /dev/null and b/cli/ballerina-cli/src/test/resources/test-resources/buildToolResources/tools/dummy-tool-pkg/resources/sample-dummy-build-tool-1.4.0.jar differ diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-bal-project-with-invalid-dependency-array.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-bal-project-with-invalid-dependency-array.txt new file mode 100644 index 000000000000..cc5605a3d92b --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-bal-project-with-invalid-dependency-array.txt @@ -0,0 +1,12 @@ +Compiling source + foo/winery:0.1.0 +ERROR [Ballerina.toml:(7:7,7:19)] invalid 'org' under [[dependency]]: 'org' can only contain alphanumerics and underscores +ERROR [Ballerina.toml:(8:8,8:15)] invalid 'name' under [[dependency]]: 'name' can only contain alphanumerics, underscores and periods +ERROR [Ballerina.toml:(9:11,9:19)] invalid 'version' under [[dependency]]: 'version' should be compatible with semver +ERROR [Ballerina.toml:(12:1,16:21)] 'name' under [[dependency]] is missing +ERROR [Ballerina.toml:(12:1,16:21)] 'org' under [[dependency]] is missing +ERROR [Ballerina.toml:(12:1,16:21)] 'version' under [[dependency]] is missing +ERROR [Ballerina.toml:(13:1,13:19)] key 'org1' not supported in schema 'dependency' +ERROR [Ballerina.toml:(14:1,14:15)] key 'name2' not supported in schema 'dependency' +ERROR [Ballerina.toml:(15:1,15:19)] key 'version3' not supported in schema 'dependency' +ERROR [main.bal:(2:13,2:20)] incompatible types: expected 'int', found 'string' diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-empty-nondefault-module.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-empty-nondefault-module.txt index f861586b4830..d3918962590f 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-empty-nondefault-module.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-empty-nondefault-module.txt @@ -1 +1 @@ -ballerina: package is empty. Please add at least one .bal file. +error: package is empty. Please add at least one .bal file. \ No newline at end of file diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-empty-package.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-empty-package.txt index f861586b4830..d3918962590f 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-empty-package.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-empty-package.txt @@ -1 +1 @@ -ballerina: package is empty. Please add at least one .bal file. +error: package is empty. Please add at least one .bal file. \ No newline at end of file diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-empty-project-with-build-tools.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-empty-project-with-build-tools.txt new file mode 100644 index 000000000000..b3bd9fbed5c5 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-empty-project-with-build-tools.txt @@ -0,0 +1,9 @@ + +Executing Build Tools + generate_file(generate_client) + +Compiling source + foo/winery:0.1.0 + +Generating executable + target/bin/winery.jar diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-empty-project-with-compiler-plugin.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-empty-project-with-compiler-plugin.txt index f861586b4830..d3918962590f 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-empty-project-with-compiler-plugin.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-empty-project-with-compiler-plugin.txt @@ -1 +1 @@ -ballerina: package is empty. Please add at least one .bal file. +error: package is empty. Please add at least one .bal file. \ No newline at end of file diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-project-wo-root-pkg-in-deps-toml.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-project-wo-root-pkg-in-deps-toml.txt index 0e303cf8fb3a..5901a45f225a 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-project-wo-root-pkg-in-deps-toml.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-project-wo-root-pkg-in-deps-toml.txt @@ -1,5 +1,6 @@ Compiling source foo/winery:0.1.0 +WARNING [Dependencies.toml:(6:1,15:2)] Detected corrupted Dependencies.toml file. This will be updated to latest dependencies. WARNING [main.bal:(6:4,6:58)] unused variable 'isSuccess' Creating bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-lt-24-build-file.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-lt-24-build-file.txt index 050932cbd5fd..e69dc6f3f12a 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-lt-24-build-file.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-lt-24-build-file.txt @@ -1,4 +1,3 @@ Executing Build Tools ERROR [Ballerina.toml:(6:1,10:24)] Build tool 'dummy_tool:1.3.0' cannot be resolved - diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-offline-resolve-failed-wo-version.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-offline-resolve-failed-wo-version.txt index 5d7ef543e0de..ee003828e127 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-offline-resolve-failed-wo-version.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-offline-resolve-failed-wo-version.txt @@ -1,4 +1,3 @@ Executing Build Tools ERROR [Ballerina.toml:(6:1,10:24)] Build tool 'dummy_tool' cannot be resolved - diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-offline-resolve-failed.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-offline-resolve-failed.txt index a2b737652d4b..b7a0b40d4275 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-offline-resolve-failed.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-offline-resolve-failed.txt @@ -1,4 +1,3 @@ Executing Build Tools ERROR [Ballerina.toml:(6:1,10:24)] Build tool 'nonexistent:1.4.0' cannot be resolved - diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-offline-with-new-major-version-locked.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-offline-with-new-major-version-locked.txt index 02bc467b6c31..91c86b53d53c 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-offline-with-new-major-version-locked.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-offline-with-new-major-version-locked.txt @@ -1,4 +1,3 @@ Executing Build Tools ERROR [Ballerina.toml:(6:1,10:24)] Build tool 'dummy_tool:2.0.0' cannot be resolved - diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-with-sticky.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-with-sticky.txt index 73ffb5c42957..661333eb87de 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-with-sticky.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/build-tool-with-sticky.txt @@ -1,4 +1,3 @@ Executing Build Tools ERROR [Ballerina.toml:(6:1,10:24)] Build tool 'dummy_tool:1.3.5' cannot be resolved - diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/clean-non-existent-target.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/clean-non-existent-target.txt index 503dc059688d..5322bf086131 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/clean-non-existent-target.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/clean-non-existent-target.txt @@ -1,2 +1 @@ ballerina: provided target directory '%TARGET_LOCATION%' does not exist. -Existing generated directory was not found diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/clean-regular-file.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/clean-regular-file.txt index 5093562bd3cd..56a9f68733d2 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/clean-regular-file.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/clean-regular-file.txt @@ -1,2 +1 @@ ballerina: provided target path '%TARGET_LOCATION%' is not a directory. -Existing generated directory was not found diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/corrupted-dependencies-toml.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/corrupted-dependencies-toml.txt new file mode 100644 index 000000000000..d7995f8662e1 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/corrupted-dependencies-toml.txt @@ -0,0 +1,6 @@ +Compiling source + luheerathan/test1:0.1.0 +WARNING [Dependencies.toml:(6:1,18:1)] Detected corrupted Dependencies.toml file. Dependencies will be updated to the latest versions. + +Generating executable + target/bin/test1.jar diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/graph-empty-project-with-build-tools.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/graph-empty-project-with-build-tools.txt new file mode 100644 index 000000000000..ddb7ad6836bf --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/graph-empty-project-with-build-tools.txt @@ -0,0 +1,11 @@ +Executing Build Tools + generate_file(generate_client) + + +digraph "foo/winery:0.1.0" { + node [shape=record] + "foo/winery" [label="<0.1.0> foo/winery:0.1.0"]; + + // Edges + +} \ No newline at end of file diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-empty-package.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-empty-package.txt index f861586b4830..d3918962590f 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-empty-package.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-empty-package.txt @@ -1 +1 @@ -ballerina: package is empty. Please add at least one .bal file. +error: package is empty. Please add at least one .bal file. \ No newline at end of file diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-empty-project-with-build-tools.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-empty-project-with-build-tools.txt new file mode 100644 index 000000000000..42fd76ca4abd --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-empty-project-with-build-tools.txt @@ -0,0 +1,9 @@ + +Executing Build Tools + generate_file(generate_client) + +Compiling source + foo/winery:0.1.0 + +Creating bala + target/bala/foo-winery-any-0.1.0.bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal1.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal1.txt new file mode 100644 index 000000000000..2d63faf99605 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal1.txt @@ -0,0 +1,5 @@ +Compiling source + sameera/myproject:0.1.0 + +Creating bala + target/bala/sameera-myproject-java17-0.1.0.bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal2.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal2.txt new file mode 100644 index 000000000000..095212c4bf36 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal2.txt @@ -0,0 +1,16 @@ +Compiling source + sameera/myproject:0.1.0 + +Creating bala + +************************************************************ +* WARNING: Package is not compatible with GraalVM. * +************************************************************ + +The package 'myproject' has been marked with its GraalVM compatibility property set to false. This setting suggests potential compatibility issues with GraalVM. + +To ensure this package can function seamlessly with GraalVM, it's recommended to either modify the package dependencies or consider GraalVM-compatible alternatives. + +************************************************************ + + target/bala/sameera-myproject-java17-0.1.0.bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal3.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal3.txt new file mode 100644 index 000000000000..095212c4bf36 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal3.txt @@ -0,0 +1,16 @@ +Compiling source + sameera/myproject:0.1.0 + +Creating bala + +************************************************************ +* WARNING: Package is not compatible with GraalVM. * +************************************************************ + +The package 'myproject' has been marked with its GraalVM compatibility property set to false. This setting suggests potential compatibility issues with GraalVM. + +To ensure this package can function seamlessly with GraalVM, it's recommended to either modify the package dependencies or consider GraalVM-compatible alternatives. + +************************************************************ + + target/bala/sameera-myproject-java17-0.1.0.bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal4.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal4.txt new file mode 100644 index 000000000000..f0062bbdaa94 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal4.txt @@ -0,0 +1,16 @@ +Compiling source + sameera/myproject:0.1.0 + +Creating bala + +************************************************************ +* WARNING: Package is not verified with GraalVM. * +************************************************************ + +The GraalVM compatibility property has not been defined for the package 'myproject'. This could potentially lead to compatibility issues with GraalVM. + +To resolve this warning, please ensure that all Java dependencies of this package are compatible with GraalVM. Subsequently, update the Ballerina.toml file under the section '[platform.java17]' with the attribute 'graalvmCompatible = true'.Or, add 'graalvmCompatible = true' attribute to each Java dependency entry in Ballerina.toml. + +************************************************************ + + target/bala/sameera-myproject-java17-0.1.0.bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal5.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal5.txt new file mode 100644 index 000000000000..095212c4bf36 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal5.txt @@ -0,0 +1,16 @@ +Compiling source + sameera/myproject:0.1.0 + +Creating bala + +************************************************************ +* WARNING: Package is not compatible with GraalVM. * +************************************************************ + +The package 'myproject' has been marked with its GraalVM compatibility property set to false. This setting suggests potential compatibility issues with GraalVM. + +To ensure this package can function seamlessly with GraalVM, it's recommended to either modify the package dependencies or consider GraalVM-compatible alternatives. + +************************************************************ + + target/bala/sameera-myproject-java17-0.1.0.bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal6.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal6.txt new file mode 100644 index 000000000000..095212c4bf36 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal6.txt @@ -0,0 +1,16 @@ +Compiling source + sameera/myproject:0.1.0 + +Creating bala + +************************************************************ +* WARNING: Package is not compatible with GraalVM. * +************************************************************ + +The package 'myproject' has been marked with its GraalVM compatibility property set to false. This setting suggests potential compatibility issues with GraalVM. + +To ensure this package can function seamlessly with GraalVM, it's recommended to either modify the package dependencies or consider GraalVM-compatible alternatives. + +************************************************************ + + target/bala/sameera-myproject-java17-0.1.0.bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal7.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal7.txt new file mode 100644 index 000000000000..095212c4bf36 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs-graal7.txt @@ -0,0 +1,16 @@ +Compiling source + sameera/myproject:0.1.0 + +Creating bala + +************************************************************ +* WARNING: Package is not compatible with GraalVM. * +************************************************************ + +The package 'myproject' has been marked with its GraalVM compatibility property set to false. This setting suggests potential compatibility issues with GraalVM. + +To ensure this package can function seamlessly with GraalVM, it's recommended to either modify the package dependencies or consider GraalVM-compatible alternatives. + +************************************************************ + + target/bala/sameera-myproject-java17-0.1.0.bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs.txt index 0741522e0fb8..f0062bbdaa94 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/pack-project-with-platform-libs.txt @@ -9,7 +9,7 @@ Creating bala The GraalVM compatibility property has not been defined for the package 'myproject'. This could potentially lead to compatibility issues with GraalVM. -To resolve this warning, please ensure that all Java dependencies of this package are compatible with GraalVM. Subsequently, update the Ballerina.toml file under the section '[platform.java17]' with the attribute 'graalvmCompatible = true'. +To resolve this warning, please ensure that all Java dependencies of this package are compatible with GraalVM. Subsequently, update the Ballerina.toml file under the section '[platform.java17]' with the attribute 'graalvmCompatible = true'.Or, add 'graalvmCompatible = true' attribute to each Java dependency entry in Ballerina.toml. ************************************************************ diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/profile-empty-project-with-build-tools.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/profile-empty-project-with-build-tools.txt new file mode 100644 index 000000000000..b3bd9fbed5c5 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/profile-empty-project-with-build-tools.txt @@ -0,0 +1,9 @@ + +Executing Build Tools + generate_file(generate_client) + +Compiling source + foo/winery:0.1.0 + +Generating executable + target/bin/winery.jar diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/run-empty-project-with-build-tools.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/run-empty-project-with-build-tools.txt new file mode 100644 index 000000000000..a913e9323177 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/run-empty-project-with-build-tools.txt @@ -0,0 +1,9 @@ + +Executing Build Tools + generate_file(generate_client) + +Compiling source + foo/winery:0.1.0 + +Running executable + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/test-empty-project-with-build-tools.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/test-empty-project-with-build-tools.txt new file mode 100644 index 000000000000..5998be05c90d --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/test-empty-project-with-build-tools.txt @@ -0,0 +1,7 @@ + +Executing Build Tools + generate_file(generate_client) + +Compiling source + foo/winery:0.1.0 + No tests found diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-correct-service-file-correct-change.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-correct-service-file-correct-change.txt new file mode 100644 index 000000000000..ae3a1ee38286 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-correct-service-file-correct-change.txt @@ -0,0 +1,14 @@ +Compiling source + INSERT_PROJECT_NAME +WARNING [:(1:1,1:1)] Skipped adding the generated source file with prefix "dummyfunc". Source file generation is not supported with standalone bal files + +Running executable + + +Detected file changes. Re-running the project... +Compiling source + INSERT_PROJECT_NAME +WARNING [:(1:1,1:1)] Skipped adding the generated source file with prefix "dummyfunc". Source file generation is not supported with standalone bal files + +Running executable + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-correct-service-file-error-change.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-correct-service-file-error-change.txt new file mode 100644 index 000000000000..06b67c871dd7 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-correct-service-file-error-change.txt @@ -0,0 +1,13 @@ +Compiling source + INSERT_PROJECT_NAME +WARNING [:(1:1,1:1)] Skipped adding the generated source file with prefix "dummyfunc". Source file generation is not supported with standalone bal files + +Running executable + + +Detected file changes. Re-running the project... +Compiling source + INSERT_PROJECT_NAME +WARNING [:(1:1,1:1)] Skipped adding the generated source file with prefix "dummyfunc". Source file generation is not supported with standalone bal files +ERROR [INSERT_PROJECT_NAME:(17:1,17:1)] missing semicolon token +error: compilation contains errors diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-correct-service-project-correct-change.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-correct-service-project-correct-change.txt new file mode 100644 index 000000000000..77dcb5d68682 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-correct-service-project-correct-change.txt @@ -0,0 +1,26 @@ +Compiling source + gayaldassanayake/service:0.1.0 + +Running executable + + +Detected file changes. Re-running the project... +Compiling source + gayaldassanayake/service:0.1.0 + +Running executable + + +Detected file changes. Re-running the project... +Compiling source + gayaldassanayake/service:0.1.0 + +Running executable + + +Detected file changes. Re-running the project... +Compiling source + gayaldassanayake/service:0.1.0 + +Running executable + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-error-service-file-correct-change.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-error-service-file-correct-change.txt new file mode 100644 index 000000000000..6c9d0b1b8de9 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-error-service-file-correct-change.txt @@ -0,0 +1,13 @@ +Compiling source + INSERT_PROJECT_NAME +WARNING [:(1:1,1:1)] Skipped adding the generated source file with prefix "dummyfunc". Source file generation is not supported with standalone bal files +ERROR [INSERT_PROJECT_NAME:(17:1,17:1)] missing semicolon token +error: compilation contains errors + +Detected file changes. Re-running the project... +Compiling source + INSERT_PROJECT_NAME +WARNING [:(1:1,1:1)] Skipped adding the generated source file with prefix "dummyfunc". Source file generation is not supported with standalone bal files + +Running executable + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-no-service-file.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-no-service-file.txt new file mode 100644 index 000000000000..903d4cde4f1e --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-no-service-file.txt @@ -0,0 +1,7 @@ +Compiling source + INSERT_PROJECT_NAME +WARNING [:(1:1,1:1)] Skipped adding the generated source file with prefix "dummyfunc". Source file generation is not supported with standalone bal files +WARNING [INSERT_PROJECT_NAME:(3:5,3:19)] unused variable 'y' + +Running executable + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-no-service-project.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-no-service-project.txt new file mode 100644 index 000000000000..0661f8043992 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-no-service-project.txt @@ -0,0 +1,5 @@ +Compiling source + gayaldassanayake/main:0.1.0 + +Running executable + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-service-project-invalid-changes.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-service-project-invalid-changes.txt new file mode 100644 index 000000000000..74b3a0160cfb --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-service-project-invalid-changes.txt @@ -0,0 +1,5 @@ +Compiling source + gayaldassanayake/service:0.1.0 + +Running executable + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-service-project-valid-changes.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-service-project-valid-changes.txt new file mode 100644 index 000000000000..fbcb07f92993 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/unix/watch-service-project-valid-changes.txt @@ -0,0 +1,26 @@ +Compiling source + gayaldassanayake/service:0.1.0 + +Running executable + + +Detected file changes. Re-running the project... +Compiling source + gayaldassanayake/service:0.1.1 + +Running executable + + +Detected file changes. Re-running the project... +Compiling source + gayaldassanayake/service:0.1.1 + +Running executable + + +Detected file changes. Re-running the project... +Compiling source + gayaldassanayake/service:0.1.1 + +Running executable + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-bal-project-with-invalid-dependency-array.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-bal-project-with-invalid-dependency-array.txt new file mode 100644 index 000000000000..cc5605a3d92b --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-bal-project-with-invalid-dependency-array.txt @@ -0,0 +1,12 @@ +Compiling source + foo/winery:0.1.0 +ERROR [Ballerina.toml:(7:7,7:19)] invalid 'org' under [[dependency]]: 'org' can only contain alphanumerics and underscores +ERROR [Ballerina.toml:(8:8,8:15)] invalid 'name' under [[dependency]]: 'name' can only contain alphanumerics, underscores and periods +ERROR [Ballerina.toml:(9:11,9:19)] invalid 'version' under [[dependency]]: 'version' should be compatible with semver +ERROR [Ballerina.toml:(12:1,16:21)] 'name' under [[dependency]] is missing +ERROR [Ballerina.toml:(12:1,16:21)] 'org' under [[dependency]] is missing +ERROR [Ballerina.toml:(12:1,16:21)] 'version' under [[dependency]] is missing +ERROR [Ballerina.toml:(13:1,13:19)] key 'org1' not supported in schema 'dependency' +ERROR [Ballerina.toml:(14:1,14:15)] key 'name2' not supported in schema 'dependency' +ERROR [Ballerina.toml:(15:1,15:19)] key 'version3' not supported in schema 'dependency' +ERROR [main.bal:(2:13,2:20)] incompatible types: expected 'int', found 'string' diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-empty-nondefault-module.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-empty-nondefault-module.txt index f861586b4830..d3918962590f 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-empty-nondefault-module.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-empty-nondefault-module.txt @@ -1 +1 @@ -ballerina: package is empty. Please add at least one .bal file. +error: package is empty. Please add at least one .bal file. \ No newline at end of file diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-empty-package.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-empty-package.txt index f861586b4830..d3918962590f 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-empty-package.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-empty-package.txt @@ -1 +1 @@ -ballerina: package is empty. Please add at least one .bal file. +error: package is empty. Please add at least one .bal file. \ No newline at end of file diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-empty-project-with-build-tools.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-empty-project-with-build-tools.txt new file mode 100644 index 000000000000..b3bd9fbed5c5 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-empty-project-with-build-tools.txt @@ -0,0 +1,9 @@ + +Executing Build Tools + generate_file(generate_client) + +Compiling source + foo/winery:0.1.0 + +Generating executable + target/bin/winery.jar diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-empty-project-with-compiler-plugin.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-empty-project-with-compiler-plugin.txt index f861586b4830..d3918962590f 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-empty-project-with-compiler-plugin.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-empty-project-with-compiler-plugin.txt @@ -1 +1 @@ -ballerina: package is empty. Please add at least one .bal file. +error: package is empty. Please add at least one .bal file. \ No newline at end of file diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-project-wo-root-pkg-in-deps-toml.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-project-wo-root-pkg-in-deps-toml.txt index 0b066c0ca102..fa4f3ffa61a8 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-project-wo-root-pkg-in-deps-toml.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-project-wo-root-pkg-in-deps-toml.txt @@ -1,5 +1,6 @@ Compiling source foo/winery:0.1.0 +WARNING [Dependencies.toml:(6:1,15:2)] Detected corrupted Dependencies.toml file. This will be updated to latest dependencies. WARNING [main.bal:(6:4,6:58)] unused variable 'isSuccess' Creating bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-lt-24-build-file.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-lt-24-build-file.txt index 050932cbd5fd..e69dc6f3f12a 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-lt-24-build-file.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-lt-24-build-file.txt @@ -1,4 +1,3 @@ Executing Build Tools ERROR [Ballerina.toml:(6:1,10:24)] Build tool 'dummy_tool:1.3.0' cannot be resolved - diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-offline-resolve-failed-wo-version.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-offline-resolve-failed-wo-version.txt index 5d7ef543e0de..ee003828e127 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-offline-resolve-failed-wo-version.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-offline-resolve-failed-wo-version.txt @@ -1,4 +1,3 @@ Executing Build Tools ERROR [Ballerina.toml:(6:1,10:24)] Build tool 'dummy_tool' cannot be resolved - diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-offline-resolve-failed.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-offline-resolve-failed.txt index a2b737652d4b..b7a0b40d4275 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-offline-resolve-failed.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-offline-resolve-failed.txt @@ -1,4 +1,3 @@ Executing Build Tools ERROR [Ballerina.toml:(6:1,10:24)] Build tool 'nonexistent:1.4.0' cannot be resolved - diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-offline-with-new-major-version-locked.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-offline-with-new-major-version-locked.txt index 02bc467b6c31..91c86b53d53c 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-offline-with-new-major-version-locked.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-offline-with-new-major-version-locked.txt @@ -1,4 +1,3 @@ Executing Build Tools ERROR [Ballerina.toml:(6:1,10:24)] Build tool 'dummy_tool:2.0.0' cannot be resolved - diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-with-sticky.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-with-sticky.txt index 73ffb5c42957..661333eb87de 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-with-sticky.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/build-tool-with-sticky.txt @@ -1,4 +1,3 @@ Executing Build Tools ERROR [Ballerina.toml:(6:1,10:24)] Build tool 'dummy_tool:1.3.5' cannot be resolved - diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/clean-non-existent-target.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/clean-non-existent-target.txt index 503dc059688d..5322bf086131 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/clean-non-existent-target.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/clean-non-existent-target.txt @@ -1,2 +1 @@ ballerina: provided target directory '%TARGET_LOCATION%' does not exist. -Existing generated directory was not found diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/clean-regular-file.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/clean-regular-file.txt index 5093562bd3cd..56a9f68733d2 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/clean-regular-file.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/clean-regular-file.txt @@ -1,2 +1 @@ ballerina: provided target path '%TARGET_LOCATION%' is not a directory. -Existing generated directory was not found diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/corrupted-dependencies-toml.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/corrupted-dependencies-toml.txt new file mode 100644 index 000000000000..79554d36dd69 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/corrupted-dependencies-toml.txt @@ -0,0 +1,6 @@ +Compiling source + luheerathan/test1:0.1.0 +WARNING [Dependencies.toml:(6:1,18:1)] Detected corrupted Dependencies.toml file. Dependencies will be updated to the latest versions. + +Generating executable + target\bin\test1.jar diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/graph-empty-project-with-build-tools.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/graph-empty-project-with-build-tools.txt new file mode 100644 index 000000000000..ddb7ad6836bf --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/graph-empty-project-with-build-tools.txt @@ -0,0 +1,11 @@ +Executing Build Tools + generate_file(generate_client) + + +digraph "foo/winery:0.1.0" { + node [shape=record] + "foo/winery" [label="<0.1.0> foo/winery:0.1.0"]; + + // Edges + +} \ No newline at end of file diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-empty-package.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-empty-package.txt index f861586b4830..d3918962590f 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-empty-package.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-empty-package.txt @@ -1 +1 @@ -ballerina: package is empty. Please add at least one .bal file. +error: package is empty. Please add at least one .bal file. \ No newline at end of file diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-empty-project-with-build-tools.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-empty-project-with-build-tools.txt new file mode 100644 index 000000000000..42fd76ca4abd --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-empty-project-with-build-tools.txt @@ -0,0 +1,9 @@ + +Executing Build Tools + generate_file(generate_client) + +Compiling source + foo/winery:0.1.0 + +Creating bala + target/bala/foo-winery-any-0.1.0.bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal1.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal1.txt new file mode 100644 index 000000000000..d8a99d53141a --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal1.txt @@ -0,0 +1,5 @@ +Compiling source + sameera/myproject:0.1.0 + +Creating bala + target\bala\sameera-myproject-java17-0.1.0.bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal2.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal2.txt new file mode 100644 index 000000000000..f7e7455fb5f7 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal2.txt @@ -0,0 +1,16 @@ +Compiling source + sameera/myproject:0.1.0 + +Creating bala + +************************************************************ +* WARNING: Package is not compatible with GraalVM. * +************************************************************ + +The package 'myproject' has been marked with its GraalVM compatibility property set to false. This setting suggests potential compatibility issues with GraalVM. + +To ensure this package can function seamlessly with GraalVM, it's recommended to either modify the package dependencies or consider GraalVM-compatible alternatives. + +************************************************************ + + target\bala\sameera-myproject-java17-0.1.0.bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal3.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal3.txt new file mode 100644 index 000000000000..f7e7455fb5f7 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal3.txt @@ -0,0 +1,16 @@ +Compiling source + sameera/myproject:0.1.0 + +Creating bala + +************************************************************ +* WARNING: Package is not compatible with GraalVM. * +************************************************************ + +The package 'myproject' has been marked with its GraalVM compatibility property set to false. This setting suggests potential compatibility issues with GraalVM. + +To ensure this package can function seamlessly with GraalVM, it's recommended to either modify the package dependencies or consider GraalVM-compatible alternatives. + +************************************************************ + + target\bala\sameera-myproject-java17-0.1.0.bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal4.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal4.txt new file mode 100644 index 000000000000..879a7e42630b --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal4.txt @@ -0,0 +1,16 @@ +Compiling source + sameera/myproject:0.1.0 + +Creating bala + +************************************************************ +* WARNING: Package is not verified with GraalVM. * +************************************************************ + +The GraalVM compatibility property has not been defined for the package 'myproject'. This could potentially lead to compatibility issues with GraalVM. + +To resolve this warning, please ensure that all Java dependencies of this package are compatible with GraalVM. Subsequently, update the Ballerina.toml file under the section '[platform.java17]' with the attribute 'graalvmCompatible = true'.Or, add 'graalvmCompatible = true' attribute to each Java dependency entry in Ballerina.toml. + +************************************************************ + + target\bala\sameera-myproject-java17-0.1.0.bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal5.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal5.txt new file mode 100644 index 000000000000..f7e7455fb5f7 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal5.txt @@ -0,0 +1,16 @@ +Compiling source + sameera/myproject:0.1.0 + +Creating bala + +************************************************************ +* WARNING: Package is not compatible with GraalVM. * +************************************************************ + +The package 'myproject' has been marked with its GraalVM compatibility property set to false. This setting suggests potential compatibility issues with GraalVM. + +To ensure this package can function seamlessly with GraalVM, it's recommended to either modify the package dependencies or consider GraalVM-compatible alternatives. + +************************************************************ + + target\bala\sameera-myproject-java17-0.1.0.bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal6.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal6.txt new file mode 100644 index 000000000000..f7e7455fb5f7 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal6.txt @@ -0,0 +1,16 @@ +Compiling source + sameera/myproject:0.1.0 + +Creating bala + +************************************************************ +* WARNING: Package is not compatible with GraalVM. * +************************************************************ + +The package 'myproject' has been marked with its GraalVM compatibility property set to false. This setting suggests potential compatibility issues with GraalVM. + +To ensure this package can function seamlessly with GraalVM, it's recommended to either modify the package dependencies or consider GraalVM-compatible alternatives. + +************************************************************ + + target\bala\sameera-myproject-java17-0.1.0.bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal7.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal7.txt new file mode 100644 index 000000000000..f7e7455fb5f7 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs-graal7.txt @@ -0,0 +1,16 @@ +Compiling source + sameera/myproject:0.1.0 + +Creating bala + +************************************************************ +* WARNING: Package is not compatible with GraalVM. * +************************************************************ + +The package 'myproject' has been marked with its GraalVM compatibility property set to false. This setting suggests potential compatibility issues with GraalVM. + +To ensure this package can function seamlessly with GraalVM, it's recommended to either modify the package dependencies or consider GraalVM-compatible alternatives. + +************************************************************ + + target\bala\sameera-myproject-java17-0.1.0.bala diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs.txt index ee964f99c893..879a7e42630b 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/pack-project-with-platform-libs.txt @@ -9,7 +9,7 @@ Creating bala The GraalVM compatibility property has not been defined for the package 'myproject'. This could potentially lead to compatibility issues with GraalVM. -To resolve this warning, please ensure that all Java dependencies of this package are compatible with GraalVM. Subsequently, update the Ballerina.toml file under the section '[platform.java17]' with the attribute 'graalvmCompatible = true'. +To resolve this warning, please ensure that all Java dependencies of this package are compatible with GraalVM. Subsequently, update the Ballerina.toml file under the section '[platform.java17]' with the attribute 'graalvmCompatible = true'.Or, add 'graalvmCompatible = true' attribute to each Java dependency entry in Ballerina.toml. ************************************************************ diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/profile-empty-project-with-build-tools.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/profile-empty-project-with-build-tools.txt new file mode 100644 index 000000000000..b3bd9fbed5c5 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/profile-empty-project-with-build-tools.txt @@ -0,0 +1,9 @@ + +Executing Build Tools + generate_file(generate_client) + +Compiling source + foo/winery:0.1.0 + +Generating executable + target/bin/winery.jar diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/run-empty-project-with-build-tools.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/run-empty-project-with-build-tools.txt new file mode 100644 index 000000000000..a913e9323177 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/run-empty-project-with-build-tools.txt @@ -0,0 +1,9 @@ + +Executing Build Tools + generate_file(generate_client) + +Compiling source + foo/winery:0.1.0 + +Running executable + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/test-empty-project-with-build-tools.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/test-empty-project-with-build-tools.txt new file mode 100644 index 000000000000..5998be05c90d --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/test-empty-project-with-build-tools.txt @@ -0,0 +1,7 @@ + +Executing Build Tools + generate_file(generate_client) + +Compiling source + foo/winery:0.1.0 + No tests found diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-pull-with-no-args.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-pull-with-no-args.txt index 2ad181e22eeb..b0eef2a40101 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-pull-with-no-args.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-pull-with-no-args.txt @@ -1,4 +1,4 @@ -ballerina: no tool id given. +ballerina: tool id is not provided. USAGE: bal tool pull [:] diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-remove-with-no-args.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-remove-with-no-args.txt index ab19bbb374af..6651e929cd6c 100644 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-remove-with-no-args.txt +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-remove-with-no-args.txt @@ -1,4 +1,4 @@ -ballerina: no tool id given. +ballerina: tool id is not provided. USAGE: bal tool remove :[] diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-use-with-invalid-tool-id.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-use-with-invalid-tool-id.txt new file mode 100644 index 000000000000..2cf31796d0dd --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-use-with-invalid-tool-id.txt @@ -0,0 +1,4 @@ +ballerina: invalid tool id. + +USAGE: + bal tool use : diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-use-with-invalid-tool-version.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-use-with-invalid-tool-version.txt new file mode 100644 index 000000000000..5bf1512508ca --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-use-with-invalid-tool-version.txt @@ -0,0 +1,4 @@ +ballerina: invalid tool version. Invalid version: '1.1'. Unexpected character 'EOI(null)' at position '3', expecting '[DOT]' + +USAGE: + bal tool use : diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-use-with-no-args.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-use-with-no-args.txt new file mode 100644 index 000000000000..b817e7995394 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-use-with-no-args.txt @@ -0,0 +1,4 @@ +ballerina: tool id is not provided. + +USAGE: + bal tool use : diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-use-with-too-many-args.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-use-with-too-many-args.txt new file mode 100644 index 000000000000..434f8cadf9b3 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/tool-use-with-too-many-args.txt @@ -0,0 +1,4 @@ +ballerina: too many arguments. + +USAGE: + bal tool use : diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-correct-service-file-correct-change.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-correct-service-file-correct-change.txt new file mode 100644 index 000000000000..ae3a1ee38286 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-correct-service-file-correct-change.txt @@ -0,0 +1,14 @@ +Compiling source + INSERT_PROJECT_NAME +WARNING [:(1:1,1:1)] Skipped adding the generated source file with prefix "dummyfunc". Source file generation is not supported with standalone bal files + +Running executable + + +Detected file changes. Re-running the project... +Compiling source + INSERT_PROJECT_NAME +WARNING [:(1:1,1:1)] Skipped adding the generated source file with prefix "dummyfunc". Source file generation is not supported with standalone bal files + +Running executable + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-correct-service-file-error-change.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-correct-service-file-error-change.txt new file mode 100644 index 000000000000..06b67c871dd7 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-correct-service-file-error-change.txt @@ -0,0 +1,13 @@ +Compiling source + INSERT_PROJECT_NAME +WARNING [:(1:1,1:1)] Skipped adding the generated source file with prefix "dummyfunc". Source file generation is not supported with standalone bal files + +Running executable + + +Detected file changes. Re-running the project... +Compiling source + INSERT_PROJECT_NAME +WARNING [:(1:1,1:1)] Skipped adding the generated source file with prefix "dummyfunc". Source file generation is not supported with standalone bal files +ERROR [INSERT_PROJECT_NAME:(17:1,17:1)] missing semicolon token +error: compilation contains errors diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-correct-service-project-correct-change.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-correct-service-project-correct-change.txt new file mode 100644 index 000000000000..77dcb5d68682 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-correct-service-project-correct-change.txt @@ -0,0 +1,26 @@ +Compiling source + gayaldassanayake/service:0.1.0 + +Running executable + + +Detected file changes. Re-running the project... +Compiling source + gayaldassanayake/service:0.1.0 + +Running executable + + +Detected file changes. Re-running the project... +Compiling source + gayaldassanayake/service:0.1.0 + +Running executable + + +Detected file changes. Re-running the project... +Compiling source + gayaldassanayake/service:0.1.0 + +Running executable + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-error-service-file-correct-change.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-error-service-file-correct-change.txt new file mode 100644 index 000000000000..6c9d0b1b8de9 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-error-service-file-correct-change.txt @@ -0,0 +1,13 @@ +Compiling source + INSERT_PROJECT_NAME +WARNING [:(1:1,1:1)] Skipped adding the generated source file with prefix "dummyfunc". Source file generation is not supported with standalone bal files +ERROR [INSERT_PROJECT_NAME:(17:1,17:1)] missing semicolon token +error: compilation contains errors + +Detected file changes. Re-running the project... +Compiling source + INSERT_PROJECT_NAME +WARNING [:(1:1,1:1)] Skipped adding the generated source file with prefix "dummyfunc". Source file generation is not supported with standalone bal files + +Running executable + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-no-service-file.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-no-service-file.txt new file mode 100644 index 000000000000..903d4cde4f1e --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-no-service-file.txt @@ -0,0 +1,7 @@ +Compiling source + INSERT_PROJECT_NAME +WARNING [:(1:1,1:1)] Skipped adding the generated source file with prefix "dummyfunc". Source file generation is not supported with standalone bal files +WARNING [INSERT_PROJECT_NAME:(3:5,3:19)] unused variable 'y' + +Running executable + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-no-service-project.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-no-service-project.txt new file mode 100644 index 000000000000..0661f8043992 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-no-service-project.txt @@ -0,0 +1,5 @@ +Compiling source + gayaldassanayake/main:0.1.0 + +Running executable + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-service-project-invalid-changes.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-service-project-invalid-changes.txt new file mode 100644 index 000000000000..74b3a0160cfb --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-service-project-invalid-changes.txt @@ -0,0 +1,5 @@ +Compiling source + gayaldassanayake/service:0.1.0 + +Running executable + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-service-project-valid-changes.txt b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-service-project-valid-changes.txt new file mode 100644 index 000000000000..fbcb07f92993 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/command-outputs/windows/watch-service-project-valid-changes.txt @@ -0,0 +1,26 @@ +Compiling source + gayaldassanayake/service:0.1.0 + +Running executable + + +Detected file changes. Re-running the project... +Compiling source + gayaldassanayake/service:0.1.1 + +Running executable + + +Detected file changes. Re-running the project... +Compiling source + gayaldassanayake/service:0.1.1 + +Running executable + + +Detected file changes. Re-running the project... +Compiling source + gayaldassanayake/service:0.1.1 + +Running executable + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/command-util/hello_template_project/Dependencies.toml b/cli/ballerina-cli/src/test/resources/test-resources/command-util/hello_template_project/Dependencies.toml deleted file mode 100644 index 11bf9d82b1b9..000000000000 --- a/cli/ballerina-cli/src/test/resources/test-resources/command-util/hello_template_project/Dependencies.toml +++ /dev/null @@ -1,81 +0,0 @@ -# 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" - -[[package]] -org = "ballerina" -name = "observe" -version = "1.0.4" -dependencies = [ - {org = "ballerina", name = "jballerina.java"} -] - -[[package]] -org = "pramodya" -name = "hello_template_project" -version = "3.1.0" -dependencies = [ - {org = "ballerinax", name = "redis"}, - {org = "ballerina", name = "io"}, - {org = "ballerina", name = "log"} -] -modules = [ - {org = "pramodya", packageName = "hello_template_project", moduleName = "hello_template_project.module2"}, - {org = "pramodya", packageName = "hello_template_project", moduleName = "hello_template_project.module1"}, - {org = "pramodya", packageName = "hello_template_project", moduleName = "hello_template_project"} -] - -[[package]] -org = "ballerinax" -name = "redis" -version = "2.2.1" -dependencies = [ - {org = "ballerina", name = "jballerina.java"} -] -modules = [ - {org = "ballerinax", packageName = "redis", moduleName = "redis"} -] - -[[package]] -org = "ballerina" -name = "io" -version = "1.2.1" -dependencies = [ - {org = "ballerina", name = "lang.value"}, - {org = "ballerina", name = "jballerina.java"} -] -modules = [ - {org = "ballerina", packageName = "io", moduleName = "io"} -] - -[[package]] -org = "ballerina" -name = "log" -version = "2.2.1" -dependencies = [ - {org = "ballerina", name = "observe"}, - {org = "ballerina", name = "io"}, - {org = "ballerina", name = "lang.value"}, - {org = "ballerina", name = "jballerina.java"} -] -modules = [ - {org = "ballerina", packageName = "log", moduleName = "log"} -] - -[[package]] -org = "ballerina" -name = "lang.value" -version = "0.0.0" -dependencies = [ - {org = "ballerina", name = "jballerina.java"} -] - -[[package]] -org = "ballerina" -name = "jballerina.java" -version = "0.0.0" - diff --git a/cli/ballerina-cli/src/test/resources/test-resources/corrupted-dependecies-toml-file/Ballerina.toml b/cli/ballerina-cli/src/test/resources/test-resources/corrupted-dependecies-toml-file/Ballerina.toml new file mode 100644 index 000000000000..1532051489af --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/corrupted-dependecies-toml-file/Ballerina.toml @@ -0,0 +1,8 @@ +[package] +org = "luheerathan" +name = "test1" +version = "0.1.0" +distribution = "2201.9.0" + +[build-options] +observabilityIncluded = true diff --git a/cli/ballerina-cli/src/test/resources/test-resources/corrupted-dependecies-toml-file/Dependencies-corrected.toml b/cli/ballerina-cli/src/test/resources/test-resources/corrupted-dependecies-toml-file/Dependencies-corrected.toml new file mode 100644 index 000000000000..3c95919acd36 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/corrupted-dependecies-toml-file/Dependencies-corrected.toml @@ -0,0 +1,17 @@ +# 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 = "DIST_VERSION" + +[[package]] +org = "luheerathan" +name = "test1" +version = "0.1.0" +modules = [ + {org = "luheerathan", packageName = "test1", moduleName = "test1"} +] + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/corrupted-dependecies-toml-file/Dependencies-corrupt.toml b/cli/ballerina-cli/src/test/resources/test-resources/corrupted-dependecies-toml-file/Dependencies-corrupt.toml new file mode 100644 index 000000000000..62cbb98f45dd --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/corrupted-dependecies-toml-file/Dependencies-corrupt.toml @@ -0,0 +1,17 @@ +# 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" + +[[package]] +org = "luheerathan" +name = "test1" +version = "0.1.0" +modules = [ + {org = "luheerathan", packageName = "test1", moduleName = "test1"} +] + diff --git a/cli/ballerina-cli/src/test/resources/test-resources/corrupted-dependecies-toml-file/main.bal b/cli/ballerina-cli/src/test/resources/test-resources/corrupted-dependecies-toml-file/main.bal new file mode 100644 index 000000000000..b684ce66a33e --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/corrupted-dependecies-toml-file/main.bal @@ -0,0 +1,3 @@ +public function main() { + +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/emptyPackage/Package.md b/cli/ballerina-cli/src/test/resources/test-resources/emptyPackage/README.md similarity index 100% rename from cli/ballerina-cli/src/test/resources/test-resources/emptyPackage/Package.md rename to cli/ballerina-cli/src/test/resources/test-resources/emptyPackage/README.md diff --git a/cli/ballerina-cli/src/test/resources/test-resources/emptyPackageWithCompilerPlugin/Module.md b/cli/ballerina-cli/src/test/resources/test-resources/emptyPackageWithCompilerPlugin/Module.md deleted file mode 100644 index 8a69f51930aa..000000000000 --- a/cli/ballerina-cli/src/test/resources/test-resources/emptyPackageWithCompilerPlugin/Module.md +++ /dev/null @@ -1,6 +0,0 @@ -Prints "Hello, World!" with a main function. -[//]: # (above is the module summary) - -# Module Overview -Provides an overview about the module when generating the API documentations. -For example, refer to https://lib.ballerina.io/ballerina/io/latest diff --git a/cli/ballerina-cli/src/test/resources/test-resources/emptyPackageWithCompilerPlugin/Package.md b/cli/ballerina-cli/src/test/resources/test-resources/emptyPackageWithCompilerPlugin/README.md similarity index 100% rename from cli/ballerina-cli/src/test/resources/test-resources/emptyPackageWithCompilerPlugin/Package.md rename to cli/ballerina-cli/src/test/resources/test-resources/emptyPackageWithCompilerPlugin/README.md diff --git a/cli/ballerina-cli/src/test/resources/test-resources/emptyProjectWithBuildTool/Ballerina.toml b/cli/ballerina-cli/src/test/resources/test-resources/emptyProjectWithBuildTool/Ballerina.toml new file mode 100644 index 000000000000..83afa27d772f --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/emptyProjectWithBuildTool/Ballerina.toml @@ -0,0 +1,10 @@ +[package] +org = "foo" +name = "winery" +version = "0.1.0" + +[[tool.generate_file]] +id = "generate_client" +filePath = "delivery.json" +targetModule = "mod_generate" +options.fileName = "client" diff --git a/cli/ballerina-cli/src/test/resources/test-resources/emptyProjectWithBuildTool/Dependencies.toml b/cli/ballerina-cli/src/test/resources/test-resources/emptyProjectWithBuildTool/Dependencies.toml new file mode 100644 index 000000000000..f2dc8118f835 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/emptyProjectWithBuildTool/Dependencies.toml @@ -0,0 +1,23 @@ + # 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 = "**INSERT_DISTRIBUTION_VERSION_HERE**" + +[[package]] +org = "foo" +name = "winery" +version = "0.1.0" +modules = [ + {org = "foo", packageName = "winery", moduleName = "winery"} +] + +[[tool]] +id = "generate_file" +org = "foo" +name = "ballerina_generate_file" +version = "0.1.0" + diff --git a/cli/ballerina-cli/src/main/resources/create_cmd_templates/lib/resources/.keep b/cli/ballerina-cli/src/test/resources/test-resources/emptyProjectWithBuildTool/delivery.json similarity index 100% rename from cli/ballerina-cli/src/main/resources/create_cmd_templates/lib/resources/.keep rename to cli/ballerina-cli/src/test/resources/test-resources/emptyProjectWithBuildTool/delivery.json diff --git a/cli/ballerina-cli/src/test/resources/test-resources/invalid-dependency-array-project/Ballerina.toml b/cli/ballerina-cli/src/test/resources/test-resources/invalid-dependency-array-project/Ballerina.toml new file mode 100644 index 000000000000..554142623d49 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/invalid-dependency-array-project/Ballerina.toml @@ -0,0 +1,16 @@ +[package] +org = "foo" +name = "winery" +version = "0.1.0" + +[[dependency]] +org = "ballerina#" +name = "dat$a" +version = "0.1.0r" +repository = "local" + +[[dependency]] +org1 = "ballerina" +name2 = "data" +version3 = "0.1.0" +repository = "maven" diff --git a/cli/ballerina-cli/src/test/resources/test-resources/invalid-dependency-array-project/main.bal b/cli/ballerina-cli/src/test/resources/test-resources/invalid-dependency-array-project/main.bal new file mode 100644 index 000000000000..de275d8e4135 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/invalid-dependency-array-project/main.bal @@ -0,0 +1,3 @@ +public function main() { + int x = "hello"; +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/bala.json b/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/bala.json new file mode 100644 index 000000000000..812300d452d7 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/bala.json @@ -0,0 +1,4 @@ +{ + "bala_version": "2.0.0", + "built_by": "WSO2" +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/compiler-plugin/compiler-plugin.json b/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/compiler-plugin/compiler-plugin.json new file mode 100644 index 000000000000..3ea3d7dddcad --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/compiler-plugin/compiler-plugin.json @@ -0,0 +1,7 @@ +{ + "plugin_id": "code2cloud", + "plugin_class": "io.ballerina.c2c.C2CCompilerPlugin", + "dependency_paths": [ + "compiler-plugin/libs/cloud-compiler-plugin-2.11.3.jar" + ] +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/dependency-graph.json b/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/dependency-graph.json new file mode 100644 index 000000000000..36a2f8cbb808 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/dependency-graph.json @@ -0,0 +1,21 @@ +{ + "packages": [ + { + "org": "ballerina", + "name": "cloud", + "version": "2.11.3", + "transitive": false, + "dependencies": [], + "modules": [] + } + ], + "modules": [ + { + "org": "ballerina", + "package_name": "cloud", + "version": "2.11.3", + "module_name": "cloud", + "dependencies": [] + } + ] +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/docs/Package.md b/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/docs/Package.md new file mode 100644 index 000000000000..fc8b1b67c0a3 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/docs/Package.md @@ -0,0 +1,5 @@ +Prints "Hello, World!" with a hello function. +[//]: # (above is the package summary) + +# Package Overview +Prints "Hello, World!" as the output to the command line using a hello function. diff --git a/cli/ballerina-cli/src/test/resources/test-resources/emptyPackage/Module.md b/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/docs/modules/cloud/Module.md similarity index 100% rename from cli/ballerina-cli/src/test/resources/test-resources/emptyPackage/Module.md rename to cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/docs/modules/cloud/Module.md diff --git a/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/modules/cloud/bal_cloud.bal b/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/modules/cloud/bal_cloud.bal new file mode 100644 index 000000000000..7a0681e5344c --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/modules/cloud/bal_cloud.bal @@ -0,0 +1,10 @@ +# Returns the string `Hello` with the input string name. +# +# + name - name as a string +# + return - "Hello, " with the input string name +public function hello(string name) returns string { + if !(name is "") { + return "Hello, " + name; + } + return "Hello, World!"; +} diff --git a/observelib/observe/src/main/ballerina/modules/mockextension/Module.md b/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/modules/cloud/resources/.keep similarity index 100% rename from observelib/observe/src/main/ballerina/modules/mockextension/Module.md rename to cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/modules/cloud/resources/.keep diff --git a/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/package.json b/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/package.json new file mode 100644 index 000000000000..2ecc05072275 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/mocked-local-repo/local/ballerina/cloud/2.11.3/any/package.json @@ -0,0 +1,14 @@ +{ + "organization": "ballerina", + "name": "cloud", + "version": "2.11.3", + "export": [ + "cloud" + ], + "ballerina_version": "2201.8.5", + "implementation_vendor": "WSO2", + "language_spec_version": "2023R1", + "platform": "any", + "graalvmCompatible": true, + "template": false +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/projectWithMocks/Ballerina.toml b/cli/ballerina-cli/src/test/resources/test-resources/projectWithMocks/Ballerina.toml new file mode 100644 index 000000000000..8a0a9dc61bb4 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/projectWithMocks/Ballerina.toml @@ -0,0 +1,4 @@ +[package] +org = "foo" +name = "projectWithMocks" +version = "0.1.0" diff --git a/cli/ballerina-cli/src/test/resources/test-resources/projectWithMocks/main.bal b/cli/ballerina-cli/src/test/resources/test-resources/projectWithMocks/main.bal new file mode 100644 index 000000000000..54131c6f50e8 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/projectWithMocks/main.bal @@ -0,0 +1,3 @@ +public function intAdd(int x, int y) returns int { + return x + y; +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/projectWithMocks/modules/mod1/mod1.bal b/cli/ballerina-cli/src/test/resources/test-resources/projectWithMocks/modules/mod1/mod1.bal new file mode 100644 index 000000000000..b114e273e3b0 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/projectWithMocks/modules/mod1/mod1.bal @@ -0,0 +1,3 @@ +public function intSub(int x, int y) returns int { + return x - y; +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/projectWithMocks/modules/mod1/tests/lib_test.bal b/cli/ballerina-cli/src/test/resources/test-resources/projectWithMocks/modules/mod1/tests/lib_test.bal new file mode 100644 index 000000000000..063fa7cfcd51 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/projectWithMocks/modules/mod1/tests/lib_test.bal @@ -0,0 +1,13 @@ +import ballerina/test; + +@test:Mock{functionName: "intSub"} +test:MockFunction intSubMockFn = new (); + +@test:Config{} +function testMockedIntSub() { + test:when(intSubMockFn).thenReturn(23); + test:assertEquals(intSub(10, 5), 23, "Invalid result"); + + test:when(intSubMockFn).withArguments(33, 44).thenReturn(77); + test:assertEquals(intSub(33, 44), 77, "Invalid result"); +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/projectWithMocks/tests/main_test.bal b/cli/ballerina-cli/src/test/resources/test-resources/projectWithMocks/tests/main_test.bal new file mode 100644 index 000000000000..5ac4257058d3 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/projectWithMocks/tests/main_test.bal @@ -0,0 +1,19 @@ +import ballerina/test; +import projectWithMocks.mod1; + +@test:Mock{functionName: "intAdd"} +test:MockFunction intAddMockFn = new (); + +@test:Config{} +function testMockedIntAdd() { + test:when(intAddMockFn).thenReturn(23); + test:assertEquals(intAdd(10, 5), 23, "Invalid result"); + + test:when(intAddMockFn).withArguments(1000, 44).thenReturn(77); + test:assertEquals(intAdd(1000, 44), 77, "Invalid result"); +} + +@test:Config{} +function testRealIntSub() { + test:assertEquals(mod1:intSub(10, 5), 5, "Invalid result"); +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validLibraryProject/Package.md b/cli/ballerina-cli/src/test/resources/test-resources/validLibraryProject/README.md similarity index 100% rename from cli/ballerina-cli/src/test/resources/test-resources/validLibraryProject/Package.md rename to cli/ballerina-cli/src/test/resources/test-resources/validLibraryProject/README.md diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal1/Ballerina.toml b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal1/Ballerina.toml new file mode 100644 index 000000000000..ba86cda3eb2f --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal1/Ballerina.toml @@ -0,0 +1,8 @@ +[package] +org = "sameera" +name = "myproject" +version = "0.1.0" + +[[platform.java17.dependency]] +path = "./libs/one-1.0.0.jar" +graalvmCompatible = true diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal1/libs/one-1.0.0.jar b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal1/libs/one-1.0.0.jar new file mode 100644 index 000000000000..d22013058e3d Binary files /dev/null and b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal1/libs/one-1.0.0.jar differ diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal1/main.bal b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal1/main.bal new file mode 100644 index 000000000000..6d0ccb5ba65d --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal1/main.bal @@ -0,0 +1,3 @@ + +public function main() { +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal2/Ballerina.toml b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal2/Ballerina.toml new file mode 100644 index 000000000000..ec63fad03044 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal2/Ballerina.toml @@ -0,0 +1,8 @@ +[package] +org = "sameera" +name = "myproject" +version = "0.1.0" + +[[platform.java17.dependency]] +path = "./libs/one-1.0.0.jar" +graalvmCompatible = false diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal2/libs/one-1.0.0.jar b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal2/libs/one-1.0.0.jar new file mode 100644 index 000000000000..d22013058e3d Binary files /dev/null and b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal2/libs/one-1.0.0.jar differ diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal2/main.bal b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal2/main.bal new file mode 100644 index 000000000000..6d0ccb5ba65d --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal2/main.bal @@ -0,0 +1,3 @@ + +public function main() { +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal3/Ballerina.toml b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal3/Ballerina.toml new file mode 100644 index 000000000000..d41c2c3982f0 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal3/Ballerina.toml @@ -0,0 +1,15 @@ +[package] +org = "sameera" +name = "myproject" +version = "0.1.0" + +[[platform.java17.dependency]] +path = "./libs/one-1.0.0.jar" +graalvmCompatible = false + +[[platform.java17.dependency]] +path = "./libs/one-1.0.1.jar" +graalvmCompatible = true + +[[platform.java17.dependency]] +path = "./libs/one-1.0.2.jar" diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal3/libs/one-1.0.0.jar b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal3/libs/one-1.0.0.jar new file mode 100644 index 000000000000..d22013058e3d Binary files /dev/null and b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal3/libs/one-1.0.0.jar differ diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal3/libs/one-1.0.1.jar b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal3/libs/one-1.0.1.jar new file mode 100644 index 000000000000..d22013058e3d Binary files /dev/null and b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal3/libs/one-1.0.1.jar differ diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal3/libs/one-1.0.2.jar b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal3/libs/one-1.0.2.jar new file mode 100644 index 000000000000..d22013058e3d Binary files /dev/null and b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal3/libs/one-1.0.2.jar differ diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal3/main.bal b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal3/main.bal new file mode 100644 index 000000000000..6d0ccb5ba65d --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal3/main.bal @@ -0,0 +1,3 @@ + +public function main() { +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal4/Ballerina.toml b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal4/Ballerina.toml new file mode 100644 index 000000000000..2ae222682c36 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal4/Ballerina.toml @@ -0,0 +1,11 @@ +[package] +org = "sameera" +name = "myproject" +version = "0.1.0" + +[[platform.java17.dependency]] +path = "./libs/one-1.0.1.jar" +graalvmCompatible = true + +[[platform.java17.dependency]] +path = "./libs/one-1.0.2.jar" diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal4/libs/one-1.0.1.jar b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal4/libs/one-1.0.1.jar new file mode 100644 index 000000000000..d22013058e3d Binary files /dev/null and b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal4/libs/one-1.0.1.jar differ diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal4/libs/one-1.0.2.jar b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal4/libs/one-1.0.2.jar new file mode 100644 index 000000000000..d22013058e3d Binary files /dev/null and b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal4/libs/one-1.0.2.jar differ diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal4/main.bal b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal4/main.bal new file mode 100644 index 000000000000..6d0ccb5ba65d --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal4/main.bal @@ -0,0 +1,3 @@ + +public function main() { +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal5/Ballerina.toml b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal5/Ballerina.toml new file mode 100644 index 000000000000..bd7f83079d43 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal5/Ballerina.toml @@ -0,0 +1,11 @@ +[package] +org = "sameera" +name = "myproject" +version = "0.1.0" + +[platform.java17] +graalvmCompatible = true + +[[platform.java17.dependency]] +path = "./libs/one-1.0.0.jar" +graalvmCompatible = false diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal5/libs/one-1.0.0.jar b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal5/libs/one-1.0.0.jar new file mode 100644 index 000000000000..d22013058e3d Binary files /dev/null and b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal5/libs/one-1.0.0.jar differ diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal5/main.bal b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal5/main.bal new file mode 100644 index 000000000000..6d0ccb5ba65d --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal5/main.bal @@ -0,0 +1,3 @@ + +public function main() { +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal6/Ballerina.toml b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal6/Ballerina.toml new file mode 100644 index 000000000000..ff692c6b4ffe --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal6/Ballerina.toml @@ -0,0 +1,11 @@ +[package] +org = "sameera" +name = "myproject" +version = "0.1.0" + +[platform.java17] +graalvmCompatible = false + +[[platform.java17.dependency]] +path = "./libs/one-1.0.0.jar" +graalvmCompatible = true diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal6/libs/one-1.0.0.jar b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal6/libs/one-1.0.0.jar new file mode 100644 index 000000000000..d22013058e3d Binary files /dev/null and b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal6/libs/one-1.0.0.jar differ diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal6/main.bal b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal6/main.bal new file mode 100644 index 000000000000..6d0ccb5ba65d --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal6/main.bal @@ -0,0 +1,3 @@ + +public function main() { +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal7/Ballerina.toml b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal7/Ballerina.toml new file mode 100644 index 000000000000..cecc9d12115d --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal7/Ballerina.toml @@ -0,0 +1,12 @@ +[package] +org = "sameera" +name = "myproject" +version = "0.1.0" + +[[platform.java17.dependency]] +path = "./libs/one-1.0.0.jar" +graalvmCompatible = true + +[[platform.java11.dependency]] +path = "./libs/one-1.0.1.jar" +graalvmCompatible = false diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal7/libs/one-1.0.0.jar b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal7/libs/one-1.0.0.jar new file mode 100644 index 000000000000..d22013058e3d Binary files /dev/null and b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal7/libs/one-1.0.0.jar differ diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal7/libs/one-1.0.1.jar b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal7/libs/one-1.0.1.jar new file mode 100644 index 000000000000..d22013058e3d Binary files /dev/null and b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal7/libs/one-1.0.1.jar differ diff --git a/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal7/main.bal b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal7/main.bal new file mode 100644 index 000000000000..6d0ccb5ba65d --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/validProjectWithPlatformLibsGraal7/main.bal @@ -0,0 +1,3 @@ + +public function main() { +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/Ballerina-copy.toml b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/Ballerina-copy.toml new file mode 100644 index 000000000000..a91aeeec13da --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/Ballerina-copy.toml @@ -0,0 +1,5 @@ +[package] +org = "gayaldassanayake" +name = "service" +version = "0.1.1" +distribution = "2201.9.2" diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/constants.bal b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/constants.bal new file mode 100644 index 000000000000..b7aba66f8026 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/constants.bal @@ -0,0 +1 @@ +const a = "a"; \ No newline at end of file diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/hello.json b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/hello.json new file mode 100644 index 000000000000..d1ed97aa9cde --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/hello.json @@ -0,0 +1,4 @@ +{ + "a": "hello", + "b": "world" +} \ No newline at end of file diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/hello.txt b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/hello.txt new file mode 100644 index 000000000000..897fa26153b8 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/hello.txt @@ -0,0 +1,2 @@ +Hello, +World diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/main.bal b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/main.bal new file mode 100644 index 000000000000..6e8cbcecdc44 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/main.bal @@ -0,0 +1,4 @@ +public function main() { + int x = 5; + int y = x + 2; +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/main/Ballerina.toml b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/main/Ballerina.toml new file mode 100644 index 000000000000..83e591cc3172 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/main/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "gayaldassanayake" +name = "main" +version = "0.1.0" +distribution = "2201.9.2" diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/main/service.bal b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/main/service.bal new file mode 100644 index 000000000000..6b71ef415c69 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/main/service.bal @@ -0,0 +1,2 @@ +public function main() { +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/mod1.bal b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/mod1.bal new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/project-service-updated.bal b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/project-service-updated.bal new file mode 100644 index 000000000000..d2e27c56f745 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/project-service-updated.bal @@ -0,0 +1,37 @@ +public function main() {} + +public class Listener { + int port; + public function 'start() returns error? {} + + public function gracefulStop() returns error? {} + + public function immediateStop() returns error? {} + + public function detach(service object {} s) returns error? {} + + public function attach(service object {} s, string[]? name = ()) returns error? {} + + public function init(int port) { + self.port = port; + } +} + +listener Listener 'listener = new Listener(9000); + +service / on 'listener { + function init() { + } + + isolated resource function get joke() returns string { + return getJoke(); + } + + isolated resource function post joke(string joke) { + setJoke(joke); + } + + isolated resource function get jokes() returns string[] { + return []; + } +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service-error.bal b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service-error.bal new file mode 100644 index 000000000000..a2cce38999ab --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service-error.bal @@ -0,0 +1,24 @@ +public function main() {} + +public class Listener { + int port; + public function 'start() returns error? {} + + public function gracefulStop() returns error? {} + + public function immediateStop() returns error? {} + + public function detach(service object {} s) returns error? {} + + public function attach(service object {} s, string[]? name = ()) returns error? {} + + public function init(int port) { + self.port = port // Missing colon here + } +} + +listener Listener 'listener = new Listener(9000); + +service / on 'listener { + function init() {} +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service-updated.bal b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service-updated.bal new file mode 100644 index 000000000000..bf2557603187 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service-updated.bal @@ -0,0 +1,24 @@ +public function main() {} + +public class Listener { + int port; + public function 'start() returns error? {} + + public function gracefulStop() returns error? {} + + public function immediateStop() returns error? {} + + public function detach(service object {} s) returns error? {} + + public function attach(service object {} s, string[]? name = ()) returns error? {} + + public function init(int port) { + self.port = port; + } +} + +listener Listener 'listener = new Listener(9090); + +service / on 'listener { + function init() {} +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service.bal b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service.bal new file mode 100644 index 000000000000..d2f9de9acec6 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service.bal @@ -0,0 +1,24 @@ +public function main() {} + +public class Listener { + int port; + public function 'start() returns error? {} + + public function gracefulStop() returns error? {} + + public function immediateStop() returns error? {} + + public function detach(service object {} s) returns error? {} + + public function attach(service object {} s, string[]? name = ()) returns error? {} + + public function init(int port) { + self.port = port; + } +} + +listener Listener 'listener = new Listener(9000); + +service / on 'listener { + function init() {} +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service/Ballerina.toml b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service/Ballerina.toml new file mode 100644 index 000000000000..4749b4e3d8c5 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service/Ballerina.toml @@ -0,0 +1,5 @@ +[package] +org = "gayaldassanayake" +name = "service" +version = "0.1.0" +distribution = "2201.9.2" diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service/modules/mod1/tests/.gitkeep b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service/modules/mod1/tests/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service/resources/.gitkeep b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service/resources/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service/service.bal b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service/service.bal new file mode 100644 index 000000000000..66f1b01068f2 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service/service.bal @@ -0,0 +1,33 @@ +public function main() {} + +public class Listener { + int port; + public function 'start() returns error? {} + + public function gracefulStop() returns error? {} + + public function immediateStop() returns error? {} + + public function detach(service object {} s) returns error? {} + + public function attach(service object {} s, string[]? name = ()) returns error? {} + + public function init(int port) { + self.port = port; + } +} + +listener Listener 'listener = new Listener(9000); + +service / on 'listener { + function init() { + } + + isolated resource function get joke() returns string { + return getJoke(); + } + + isolated resource function post joke(string joke) { + setJoke(joke); + } +} diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service/tests/.gitkeep b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service/tests/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service/utils.bal b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service/utils.bal new file mode 100644 index 000000000000..cb1745fcba67 --- /dev/null +++ b/cli/ballerina-cli/src/test/resources/test-resources/watchFlagResources/service/utils.bal @@ -0,0 +1,6 @@ +isolated function getJoke() returns string { + return "Chuck Norris breathes air ... five times a day."; +} + +isolated function setJoke(string joke) { +} diff --git a/cli/ballerina-cli/src/test/resources/testng.xml b/cli/ballerina-cli/src/test/resources/testng.xml index 2b477f334530..8a68cc310ad4 100644 --- a/cli/ballerina-cli/src/test/resources/testng.xml +++ b/cli/ballerina-cli/src/test/resources/testng.xml @@ -45,6 +45,7 @@ under the License. + diff --git a/cli/central-client/build.gradle b/cli/central-client/build.gradle index ad57adfd59c3..29b533a76a84 100644 --- a/cli/central-client/build.gradle +++ b/cli/central-client/build.gradle @@ -15,8 +15,10 @@ * */ -apply from: "$rootDir/gradle/javaProject.gradle" -apply from: "$rootDir/gradle/ballerinaLangLibLoad.gradle" +plugins { + id 'javaProject' + id 'ballerinaLangLibLoad' +} configurations { birJar @@ -30,27 +32,28 @@ configurations { dependencies { implementation project(':ballerina-runtime') - implementation 'me.tongfei:progressbar' - implementation 'com.google.code.gson:gson' - implementation 'com.google.code.findbugs:jsr305' - implementation 'com.github.zafarkhaja:java-semver' - implementation 'commons-io:commons-io' - implementation 'com.squareup.okhttp3:okhttp' - implementation 'com.squareup.okio:okio' + implementation libs.tongfei.progressbar + implementation libs.gson + implementation libs.findbugs.jsr305 + implementation libs.zafarkhaja.jsemver + implementation libs.commons.io + implementation libs.squareup.okhttp + implementation libs.squareup.okio - testImplementation "org.mockito:mockito-core:${mockitoCoreVersion}" - testImplementation "org.mockito:mockito-testng:${mockitoTestNGVersion}" - testImplementation 'org.testng:testng' - testImplementation 'org.awaitility:awaitility' + testImplementation libs.squareup.mock.webserver + testImplementation libs.mockito.core + testImplementation libs.mockito.testng + testImplementation libs.testng + testImplementation libs.awaitility } -task createTestDistributionCache(type: Copy) { +tasks.register('createTestDistributionCache', Copy) { dependsOn configurations.distributionBala from configurations.distributionBala into "$buildDir/repo" } -task createBirCache { +tasks.register('createBirCache') { dependsOn configurations.bir doLast { @@ -87,9 +90,14 @@ ext.moduleName = 'ballerina.central.client' compileJava { inputs.property("moduleName", moduleName) doFirst { - options.compilerArgs = [ - '--module-path', classpath.asPath, - ] + options.compilerArgs << '--module-path' << classpath.asPath + classpath = files() + } +} + +javadoc { + doFirst { + options.modulePath = classpath.toList() classpath = files() } } diff --git a/cli/central-client/out/test/resources/test-resources/utils/Settings.toml b/cli/central-client/out/test/resources/test-resources/utils/Settings.toml deleted file mode 100644 index 955ed5bdccac..000000000000 --- a/cli/central-client/out/test/resources/test-resources/utils/Settings.toml +++ /dev/null @@ -1,2 +0,0 @@ -[central] -accesstoken="273cc9f6-c333-36ab-aa2q-f08e9513ff5y" diff --git a/cli/central-client/out/test/resources/test-resources/utils/package.json b/cli/central-client/out/test/resources/test-resources/utils/package.json deleted file mode 100644 index 634941f0667d..000000000000 --- a/cli/central-client/out/test/resources/test-resources/utils/package.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "organization": "foo", - "name": "winery", - "version": "1.3.5", - "platform": "any", - "languageSpecificationVersion": "2020r2", - "URL": "/foo/winery/1.3.5", - "balaVersion": "1.0.0", - "balaURL": "https://fileserver.dev-central.ballerina.io/2.0/foo/winery/1.3.5/winery-2020r2-any-1.3.5.bala", - "readme": "Connects to winery from Ballerina.", - "template": false, - "licenses": [ - "Apache-2.0" - ], - "authors": [ - "WSO2" - ], - "sourceCodeLocation": "https://github.com/foo-connectors/module-winery", - "keywords": [], - "ballerinaVersion": "Ballerina 2.0.0", - "createdDate": 1604415674965, - "modules": [ - { - "name": "default", - "summary": "", - "readme": "", - "apiDocURL": "https://docs.dev-central.ballerina.io/packages/foo/winery/1.3.5", - "packageUrl": "/foo/winery/1.3.5" - }, - { - "name": "errors", - "summary": "", - "readme": "", - "apiDocURL": "https://docs.dev-central.ballerina.io/packages/foo/winery/1.3.5/errors", - "packageUrl": "/foo/winery/1.3.5" - }, - { - "name": "utility", - "summary": "", - "readme": "", - "apiDocURL": "https://docs.dev-central.ballerina.io/packages/foo/winery/1.3.5/utility", - "packageUrl": "/foo/winery/1.3.5" - } - ] -} diff --git a/cli/central-client/out/test/resources/test-resources/utils/packageSearch.json b/cli/central-client/out/test/resources/test-resources/utils/packageSearch.json deleted file mode 100644 index 9ce92ac1303e..000000000000 --- a/cli/central-client/out/test/resources/test-resources/utils/packageSearch.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "packages": [ - { - "organization": "foo", - "name": "winery", - "version": "1.3.5", - "platform": "any", - "languageSpecificationVersion": "2020r2", - "URL": "/foo/winery/1.3.5", - "balaVersion": "1.0.0", - "balaURL": "https://fileserver.dev-central.ballerina.io/2.0/foo/winery/1.3.5/winery-2020r2-any-1.3.5.bala", - "readme": "Connects to Salewineryorce from Ballerina. \n\n# Package Overview\n\nHandle accounts with Salewineryorce.\n", - "template": false, - "licenses": [ - "Apache-2.0" - ], - "authors": [ - "WSO2" - ], - "sourceCodeLocation": "https://github.com/foo-connectors/module-winery", - "keywords": [], - "ballerinaVersion": "Ballerina 2.0.0", - "createdDate": 1604490703738, - "modules": [] - } - ], - "count": 1 -} diff --git a/cli/central-client/out/test/resources/test-resources/utils/sf-any.bala b/cli/central-client/out/test/resources/test-resources/utils/sf-any.bala deleted file mode 100644 index 40598ea49c21..000000000000 Binary files a/cli/central-client/out/test/resources/test-resources/utils/sf-any.bala and /dev/null differ diff --git a/cli/central-client/out/test/resources/testng.xml b/cli/central-client/out/test/resources/testng.xml deleted file mode 100644 index c59c60475f1b..000000000000 --- a/cli/central-client/out/test/resources/testng.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/cli/central-client/src/main/java/org/ballerinalang/central/client/CentralAPIClient.java b/cli/central-client/src/main/java/org/ballerinalang/central/client/CentralAPIClient.java index 0b55427c1426..0e4b688ec97c 100644 --- a/cli/central-client/src/main/java/org/ballerinalang/central/client/CentralAPIClient.java +++ b/cli/central-client/src/main/java/org/ballerinalang/central/client/CentralAPIClient.java @@ -27,6 +27,7 @@ import okhttp3.Call; import okhttp3.Credentials; import okhttp3.HttpUrl; +import okhttp3.Interceptor; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.OkHttpClient; @@ -53,8 +54,6 @@ import java.io.IOException; import java.io.PrintStream; import java.net.Proxy; -import java.net.SocketTimeoutException; -import java.net.UnknownHostException; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @@ -82,6 +81,7 @@ import static org.ballerinalang.central.client.CentralClientConstants.APPLICATION_OCTET_STREAM; import static org.ballerinalang.central.client.CentralClientConstants.AUTHORIZATION; import static org.ballerinalang.central.client.CentralClientConstants.BALA_URL; +import static org.ballerinalang.central.client.CentralClientConstants.BALLERINA_CENTRAL_TELEMETRY_DISABLED; import static org.ballerinalang.central.client.CentralClientConstants.BALLERINA_PLATFORM; import static org.ballerinalang.central.client.CentralClientConstants.CONTENT_DISPOSITION; import static org.ballerinalang.central.client.CentralClientConstants.CONTENT_TYPE; @@ -98,6 +98,7 @@ import static org.ballerinalang.central.client.CentralClientConstants.USER_AGENT; import static org.ballerinalang.central.client.CentralClientConstants.VERSION; import static org.ballerinalang.central.client.Utils.ProgressRequestBody; +import static org.ballerinalang.central.client.Utils.SET_TEST_MODE_ACTIVE; import static org.ballerinalang.central.client.Utils.checkHash; import static org.ballerinalang.central.client.Utils.createBalaInHomeRepo; import static org.ballerinalang.central.client.Utils.getAsList; @@ -145,6 +146,8 @@ public class CentralAPIClient { private static final int DEFAULT_READ_TIMEOUT = 60; private static final int DEFAULT_WRITE_TIMEOUT = 60; private static final int DEFAULT_CALL_TIMEOUT = 0; + private static final int MAX_RETRY = 1; + public static final String CONNECTION_RESET = "Connection reset"; private final String baseUrl; private final Proxy proxy; @@ -157,6 +160,7 @@ public class CentralAPIClient { private final int readTimeout; private final int writeTimeout; private final int callTimeout; + private final int maxRetries; public CentralAPIClient(String baseUrl, Proxy proxy, String accessToken) { this.outStream = System.out; @@ -170,11 +174,28 @@ public CentralAPIClient(String baseUrl, Proxy proxy, String accessToken) { this.readTimeout = DEFAULT_READ_TIMEOUT; this.writeTimeout = DEFAULT_WRITE_TIMEOUT; this.callTimeout = DEFAULT_CALL_TIMEOUT; + this.maxRetries = MAX_RETRY; + } + + public CentralAPIClient(String baseUrl, Proxy proxy, String accessToken, boolean verboseEnabled, int maxRetries, + PrintStream outStream) { + this.outStream = outStream; + this.baseUrl = baseUrl; + this.proxy = proxy; + this.accessToken = accessToken; + this.verboseEnabled = verboseEnabled; + this.proxyUsername = ""; + this.proxyPassword = ""; + this.connectTimeout = DEFAULT_CONNECT_TIMEOUT; + this.readTimeout = DEFAULT_READ_TIMEOUT; + this.writeTimeout = DEFAULT_WRITE_TIMEOUT; + this.callTimeout = DEFAULT_CALL_TIMEOUT; + this.maxRetries = maxRetries; } public CentralAPIClient(String baseUrl, Proxy proxy, String proxyUsername, String proxyPassword, String accessToken, int connectionTimeout, int readTimeout, int writeTimeout, - int callTimeout) { + int callTimeout, int maxRetries) { this.outStream = System.out; this.baseUrl = baseUrl; this.proxy = proxy; @@ -186,6 +207,7 @@ public CentralAPIClient(String baseUrl, Proxy proxy, String proxyUsername, Strin this.readTimeout = readTimeout; this.writeTimeout = writeTimeout; this.callTimeout = callTimeout; + this.maxRetries = maxRetries; } /** @@ -263,9 +285,6 @@ public Package getPackage(String orgNamePath, String packageNamePath, String ver } throw new CentralClientException(ERR_CANNOT_FIND_PACKAGE + packageSignature); - } catch (SocketTimeoutException e) { - throw new ConnectionErrorException(ERR_CANNOT_FIND_PACKAGE + packageSignature + ". reason: " + - e.getMessage()); } catch (IOException e) { throw new CentralClientException(ERR_CANNOT_FIND_PACKAGE + packageSignature + ". reason: " + e.getMessage()); @@ -349,9 +368,6 @@ public List getPackageVersions(String orgNamePath, String packageNamePat } throw new CentralClientException(ERR_CANNOT_FIND_VERSIONS + packageSignature + "."); - } catch (SocketTimeoutException | UnknownHostException e) { - throw new ConnectionErrorException(ERR_CANNOT_FIND_VERSIONS + packageSignature + ". reason: " + - e.getMessage()); } catch (IOException e) { throw new CentralClientException(ERR_CANNOT_FIND_VERSIONS + packageSignature + ". reason: " + e.getMessage()); @@ -492,6 +508,31 @@ public void pushPackage(Path balaPath, String org, String name, String version, * @throws CentralClientException Central Client exception. */ public void pullPackage(String org, String name, String version, Path packagePathInBalaCache, + String supportedPlatform, String ballerinaVersion, boolean isBuild) + throws CentralClientException { + int retryCount = 0; + while (retryCount <= this.maxRetries) { + try { + pullPackageInternal(org, name, version, packagePathInBalaCache, supportedPlatform, ballerinaVersion, + isBuild); + break; + } catch (CentralClientException centralClientException) { + if (centralClientException.getMessage().contains(CONNECTION_RESET) && retryCount < this.maxRetries) { + if (verboseEnabled) { + outStream.println("* Retrying to pull the package: " + org + "/" + name + ":" + version + + " due to: " + centralClientException.getMessage() + ". Retry attempt: " + + (retryCount + 1)); + outStream.println(); + } + retryCount++; + continue; + } + throw centralClientException; + } + } + } + + private void pullPackageInternal(String org, String name, String version, Path packagePathInBalaCache, String supportedPlatform, String ballerinaVersion, boolean isBuild) throws CentralClientException { String resourceUrl = PACKAGE_PATH_PREFIX + org + SEPARATOR + name; @@ -644,6 +685,31 @@ public void pullPackage(String org, String name, String version, Path packagePat * @throws CentralClientException Central Client exception. */ public String[] pullTool(String toolId, String version, Path balaCacheDirPath, String supportedPlatform, + String ballerinaVersion, boolean isBuild) throws CentralClientException { + int retryCount = 0; + String[] result = new String[0]; + while (retryCount <= this.maxRetries) { + try { + result = pullToolInternal(toolId, version, balaCacheDirPath, supportedPlatform, ballerinaVersion, + isBuild); + break; + } catch (CentralClientException centralClientException) { + if (centralClientException.getMessage().contains(CONNECTION_RESET) && retryCount < this.maxRetries) { + if (verboseEnabled) { + outStream.println("* Retrying to pull the tool: " + toolId + ":" + version + " due to: " + + centralClientException.getMessage() + ". Retry attempt: " + (retryCount + 1)); + outStream.println(); + } + retryCount++; + continue; + } + throw centralClientException; + } + } + return result; + } + + private String[] pullToolInternal(String toolId, String version, Path balaCacheDirPath, String supportedPlatform, String ballerinaVersion, boolean isBuild) throws CentralClientException { String resourceUrl = TOOL_PATH_PREFIX + toolId; boolean enableOutputStream = Boolean @@ -689,6 +755,7 @@ public String[] pullTool(String toolId, String version, Path balaCacheDirPath, S Optional latestVersion = Optional.empty(); Optional balaUrl = Optional.empty(); Optional platform = Optional.empty(); + String digest = ""; if (body.isPresent()) { Optional contentType = Optional.ofNullable(body.get().contentType()); if (contentType.isPresent() && isApplicationJsonContentType(contentType.get().toString())) { @@ -699,6 +766,7 @@ public String[] pullTool(String toolId, String version, Path balaCacheDirPath, S balaUrl = Optional.ofNullable(jsonContent.get(BALA_URL).getAsString()); platform = Optional.of(jsonContent.get(PLATFORM).getAsString()) .or(() -> Optional.of(ANY_PLATFORM)); + digest = Optional.ofNullable(jsonContent.get(DIGEST).getAsString()).orElse(""); } } @@ -724,7 +792,7 @@ public String[] pullTool(String toolId, String version, Path balaCacheDirPath, S try { createBalaInHomeRepo(balaDownloadResponse, packagePathInBalaCache, org.get(), pkgName.get(), isNightlyBuild, null, balaUrl.get(), balaFileName, - enableOutputStream ? outStream : null, logFormatter, ""); + enableOutputStream ? outStream : null, logFormatter, digest); return new String[] { String.valueOf(true), org.get(), pkgName.get(), latestVersion.get() }; } catch (PackageAlreadyExistsException ignore) { // package already exists. setting org, name and version fields is enough @@ -1524,6 +1592,7 @@ protected OkHttpClient getClient() { .followRedirects(false) .retryOnConnectionFailure(true) .proxy(this.proxy) + .addInterceptor(new CustomRetryInterceptor(this.maxRetries)) .build(); if ((!(this.proxyUsername).isEmpty() && !(this.proxyPassword).isEmpty())) { @@ -1606,16 +1675,14 @@ protected void closeClient(OkHttpClient client) throws IOException { * @return Http request builder */ protected Request.Builder getNewRequest(String supportedPlatform, String ballerinaVersion) { - if (this.accessToken.isEmpty()) { - return new Request.Builder() - .addHeader(BALLERINA_PLATFORM, supportedPlatform) - .addHeader(USER_AGENT, ballerinaVersion); - } else { - return new Request.Builder() - .addHeader(BALLERINA_PLATFORM, supportedPlatform) - .addHeader(USER_AGENT, ballerinaVersion) - .addHeader(AUTHORIZATION, getBearerToken(this.accessToken)); + Request.Builder requestBuilder = new Request.Builder() + .addHeader(BALLERINA_PLATFORM, supportedPlatform) + .addHeader(USER_AGENT, ballerinaVersion) + .addHeader(BALLERINA_CENTRAL_TELEMETRY_DISABLED, String.valueOf(SET_TEST_MODE_ACTIVE)); + if (!this.accessToken.isEmpty()) { + requestBuilder.addHeader(AUTHORIZATION, getBearerToken(this.accessToken)); } + return requestBuilder; } public String accessToken() { @@ -1750,11 +1817,10 @@ public JsonObject getTrigger(String id, String supportedPlatform, String balleri * @param org org name * @param body response body * @param responseBody error message - * @throws IOException when accessing response body * @throws CentralClientException with unauthorized error message */ private void handleUnauthorizedResponse(String org, Optional body, String responseBody) - throws IOException, CentralClientException { + throws CentralClientException { if (body.isPresent()) { Optional contentType = Optional.ofNullable(body.get().contentType()); if (contentType.isPresent() && isApplicationJsonContentType(contentType.get().toString())) { @@ -1773,11 +1839,10 @@ private void handleUnauthorizedResponse(String org, Optional body, * * @param body response body * @param responseBody error message - * @throws IOException when accessing response body * @throws CentralClientException with unauthorized error message */ private void handleUnauthorizedResponse(Optional body, String responseBody) - throws IOException, CentralClientException { + throws CentralClientException { if (body.isPresent()) { Optional contentType = Optional.ofNullable(body.get().contentType()); if (contentType.isPresent() && isApplicationJsonContentType(contentType.get().toString())) { @@ -1796,11 +1861,10 @@ private void handleUnauthorizedResponse(Optional body, String resp * * @param mediaType mediaType * @param responseBody response body - * @throws IOException when accessing response body * @throws CentralClientException with unauthorized error message */ private void handleUnauthorizedResponse(MediaType mediaType, String responseBody) - throws IOException, CentralClientException { + throws CentralClientException { Optional contentType = Optional.ofNullable(mediaType); StringBuilder message = new StringBuilder("unauthorized access token. " + "check access token set in 'Settings.toml' file."); @@ -1851,4 +1915,52 @@ private void logRequestConnectVerbose(Request request, String resourceUrl) { this.outStream.println(">"); } } + + class CustomRetryInterceptor implements Interceptor { + private final int maxRetries; + CustomRetryInterceptor(int maxRetry) { + this.maxRetries = maxRetry; + } + + @Override + public Response intercept(Chain chain) throws IOException { + int retryCount = 0; + Request request = chain.request(); + Response response = null; + while (retryCount <= maxRetries) { + response = chain.proceed(request); + if (response.code() < 500 || retryCount == maxRetries) { + return response; + } + retryCount++; + Optional body = Optional.ofNullable(response.body()); + String responseBodyString = null; + if (body.isPresent()) { + responseBodyString = body.get().string(); + } + logRetryVerbose(response, responseBodyString, request, retryCount); + response.close(); + } + return response; + } + + private void logRetryVerbose(Response response, String bodyContent, Request request, int retryCount) { + if (verboseEnabled) { + Optional body = Optional.ofNullable(response.body()); + outStream.println("< HTTP " + response.code() + " " + response.message()); + if (body.isPresent()) { + for (String headerName : response.headers().names()) { + outStream.println("> " + headerName + ": " + response.header(headerName)); + } + outStream.println("< "); + if (bodyContent != null && !bodyContent.isEmpty()) { + outStream.println(bodyContent); + } + outStream.println("* Connection to host " + baseUrl + " left intact \n"); + } + outStream.println("* Retrying request to " + request.url() + " due to " + response.code() + + " response code. Retry attempt: " + retryCount); + } + } + } } diff --git a/cli/central-client/src/main/java/org/ballerinalang/central/client/CentralClientConstants.java b/cli/central-client/src/main/java/org/ballerinalang/central/client/CentralClientConstants.java index 933ebaa160f2..6aad12746440 100644 --- a/cli/central-client/src/main/java/org/ballerinalang/central/client/CentralClientConstants.java +++ b/cli/central-client/src/main/java/org/ballerinalang/central/client/CentralClientConstants.java @@ -22,7 +22,7 @@ * * @since 1.2.0 */ -public class CentralClientConstants { +public final class CentralClientConstants { private CentralClientConstants() { } @@ -60,5 +60,6 @@ private CentralClientConstants() { public static final int UPDATE_INTERVAL_MILLIS = 1000; public static final String SHA256 = "sha-256="; public static final String SHA256_ALGORITHM = "SHA-256"; - + public static final String TEST_MODE_ACTIVE = "TEST_MODE_ACTIVE"; + public static final String BALLERINA_CENTRAL_TELEMETRY_DISABLED = "Ballerina-Central-Telemetry-Disabled"; } diff --git a/cli/central-client/src/main/java/org/ballerinalang/central/client/Utils.java b/cli/central-client/src/main/java/org/ballerinalang/central/client/Utils.java index f6526b01a973..59a6fe0c5b90 100644 --- a/cli/central-client/src/main/java/org/ballerinalang/central/client/Utils.java +++ b/cli/central-client/src/main/java/org/ballerinalang/central/client/Utils.java @@ -40,26 +40,26 @@ import java.io.BufferedWriter; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; -import java.math.BigInteger; import java.net.URI; import java.nio.charset.Charset; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.ballerinalang.central.client.CentralClientConstants.APPLICATION_JSON; import static org.ballerinalang.central.client.CentralClientConstants.BALLERINA_DEV_CENTRAL; @@ -72,18 +72,21 @@ import static org.ballerinalang.central.client.CentralClientConstants.SHA256; import static org.ballerinalang.central.client.CentralClientConstants.SHA256_ALGORITHM; import static org.ballerinalang.central.client.CentralClientConstants.STAGING_REPO; +import static org.ballerinalang.central.client.CentralClientConstants.TEST_MODE_ACTIVE; import static org.ballerinalang.central.client.CentralClientConstants.UPDATE_INTERVAL_MILLIS; /** * Utils class for this package. */ -public class Utils { +public final class Utils { + private static final int BUFFER_SIZE = 1024; public static final String DEPRECATED_META_FILE_NAME = "deprecated.txt"; public static final boolean SET_BALLERINA_STAGE_CENTRAL = Boolean.parseBoolean( System.getenv(BALLERINA_STAGE_CENTRAL)); public static final boolean SET_BALLERINA_DEV_CENTRAL = Boolean.parseBoolean( System.getenv(BALLERINA_DEV_CENTRAL)); + public static final boolean SET_TEST_MODE_ACTIVE = Boolean.parseBoolean(System.getenv(TEST_MODE_ACTIVE)); private Utils() { } @@ -100,7 +103,7 @@ public enum RequestMethod { * * @param balaDownloadResponse http response for downloading the bala file * @param pkgPathInBalaCache package path in bala cache, - * .ballerina/bala_cache// + * {@literal .ballerina/bala_cache//} * @param pkgOrg package org * @param pkgName package name * @param isNightlyBuild is nightly build @@ -143,29 +146,36 @@ public static void createBalaInHomeRepo(Response balaDownloadResponse, Path pkgP // .ballerina/bala_cache/// try { - if (Files.isDirectory(balaCacheWithPkgPath) && Files.list(balaCacheWithPkgPath).findAny().isPresent()) { - // update the existing deprecation details - Path deprecatedFilePath = balaCacheWithPkgPath.resolve(DEPRECATED_META_FILE_NAME); - if (deprecatedFilePath.toFile().exists() && deprecationMsg == null) { - // delete deprecated file if it exists - Files.delete(deprecatedFilePath); - } else if (deprecationMsg != null) { - // write deprecation details to the file - try (BufferedWriter writer = new BufferedWriter(new FileWriter(deprecatedFilePath.toFile(), - Charset.defaultCharset()))) { - writer.write(deprecationMsg); - } + if (Files.isDirectory(balaCacheWithPkgPath)) { + boolean hasChildren; + try (Stream paths = Files.list(balaCacheWithPkgPath)) { + hasChildren = paths.findAny().isPresent(); } + if (hasChildren) { + // update the existing deprecation details + Path deprecatedFilePath = balaCacheWithPkgPath.resolve(DEPRECATED_META_FILE_NAME); + if (deprecatedFilePath.toFile().exists() && deprecationMsg == null) { + // delete deprecated file if it exists + Files.delete(deprecatedFilePath); + } else if (deprecationMsg != null) { + // write deprecation details to the file + try (BufferedWriter writer = new BufferedWriter(new FileWriter(deprecatedFilePath.toFile(), + Charset.defaultCharset()))) { + writer.write(deprecationMsg); + } + } - downloadBody.ifPresent(ResponseBody::close); - throw new PackageAlreadyExistsException( - logFormatter.formatLog("package already exists in the home repository: " + - balaCacheWithPkgPath.toString())); + downloadBody.ifPresent(ResponseBody::close); + throw new PackageAlreadyExistsException( + logFormatter.formatLog("package already exists in the home repository: " + + balaCacheWithPkgPath.toString()), validPkgVersion); + } } } catch (IOException e) { downloadBody.ifPresent(ResponseBody::close); throw new PackageAlreadyExistsException( - logFormatter.formatLog("error accessing bala : " + balaCacheWithPkgPath.toString())); + logFormatter.formatLog("error accessing bala : " + balaCacheWithPkgPath.toString()), + validPkgVersion); } // Create the following temp path @@ -225,7 +235,7 @@ static String validatePackageVersion(String pkgVersion, LogFormatter logFormatte * @return bala file name */ private static String getBalaFileName(String contentDisposition, String balaFile) { - if (contentDisposition != null && !contentDisposition.equals("")) { + if (contentDisposition != null && !contentDisposition.isEmpty()) { return contentDisposition.substring("attachment; filename=".length()); } else { return balaFile; @@ -305,7 +315,7 @@ private static void handleNightlyBuild(boolean isNightlyBuild, Path balaCacheWit LogFormatter logFormatter) throws CentralClientException { if (isNightlyBuild) { // If its a nightly build tag the file as a module from nightly - Path nightlyBuildMetaFile = Paths.get(balaCacheWithPkgPath.toString(), "nightly.build"); + Path nightlyBuildMetaFile = Path.of(balaCacheWithPkgPath.toString(), "nightly.build"); if (!nightlyBuildMetaFile.toFile().exists()) { createMetaFile(nightlyBuildMetaFile, logFormatter, "error occurred while creating nightly.build file."); } @@ -323,7 +333,7 @@ private static void handlePackageDeprecation(String deprecateMsg, Path balaCache LogFormatter logFormatter) throws CentralClientException { if (deprecateMsg != null) { // If its a deprecated package tag a file to denote as deprecated - Path deprecateMsgFile = Paths.get(balaCacheWithPkgPath.toString(), DEPRECATED_META_FILE_NAME); + Path deprecateMsgFile = Path.of(balaCacheWithPkgPath.toString(), DEPRECATED_META_FILE_NAME); if (!deprecateMsgFile.toFile().exists()) { createMetaFile(deprecateMsgFile, logFormatter, "error occurred while creating the file '" + DEPRECATED_META_FILE_NAME + "'"); @@ -347,7 +357,7 @@ private static void writeAndHandleProgress(InputStream inputStream, FileOutputSt long totalSizeInKB, String fullPkgName, PrintStream outStream, LogFormatter logFormatter, Path homeRepo) throws IOException { int count; - byte[] buffer = new byte[1024]; + byte[] buffer = new byte[BUFFER_SIZE]; String remoteRepo = getRemoteRepo(); String progressBarTask = fullPkgName + " [" + remoteRepo + " ->" + homeRepo + "] "; try (ProgressBar progressBar = new ProgressBar(progressBarTask, totalSizeInKB, 1000, @@ -364,7 +374,7 @@ private static void writeAndHandleProgress(InputStream inputStream, FileOutputSt private static void writeAndHandleProgressQuietly(InputStream inputStream, FileOutputStream outputStream) throws IOException { int count; - byte[] buffer = new byte[1024]; + byte[] buffer = new byte[BUFFER_SIZE]; while ((count = inputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, count); @@ -415,8 +425,7 @@ private static void writeDeprecatedMsg(Path metaFilePath, LogFormatter logFormat * @return converted list of strings */ static List getAsList(String arrayString) { - return new Gson().fromJson(arrayString, new TypeToken>() { - }.getType()); + return new Gson().fromJson(arrayString, new TypeToken<>() { }); } /** @@ -455,7 +464,11 @@ private static void extractBala(Path balaFilePath, Path balaFileDestPath, String try (FileSystem zipFileSystem = FileSystems.newFileSystem(zipURI, new HashMap<>())) { Path packageRoot = zipFileSystem.getPath("/"); - List paths = Files.walk(packageRoot).filter(path -> path != packageRoot).collect(Collectors.toList()); + List paths; + try (Stream pathStream = Files.walk(packageRoot)) { + paths = pathStream.filter(path -> path != packageRoot).toList(); + } + for (Path path : paths) { Path destPath = balaFileDestPath.resolve(packageRoot.relativize(path).toString()); // Handle overwriting existing bala @@ -468,13 +481,37 @@ private static void extractBala(Path balaFilePath, Path balaFileDestPath, String } public static String checkHash(String filePath, String algorithm) throws CentralClientException { + MessageDigest md; try { - byte[] data = Files.readAllBytes(Paths.get(filePath)); - byte[] hash = MessageDigest.getInstance(algorithm).digest(data); - return new BigInteger(1, hash).toString(16); - } catch (IOException | NoSuchAlgorithmException e) { - throw new CentralClientException("Unable to calculate the hash value of the file: " + filePath); + md = MessageDigest.getInstance(algorithm); + } catch (NoSuchAlgorithmException e) { + throw new CentralClientException("Unable to calculate the hash value of the file " + filePath + ": " + + e.getMessage()); + } + + try (InputStream is = new FileInputStream(filePath); + DigestInputStream dis = new DigestInputStream(is, md)) { + byte[] buffer = new byte[BUFFER_SIZE]; + while (dis.read(buffer) != -1) { + } + md = dis.getMessageDigest(); + return bytesToHex(md.digest()); + } catch (RuntimeException | IOException e) { + throw new CentralClientException("Unable to calculate the hash value of the file " + filePath + ": " + + e.getMessage()); + } + } + + private static String bytesToHex(byte[] hash) { + StringBuilder hexString = new StringBuilder(2 * hash.length); + for (byte b : hash) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); } + return hexString.toString(); } static String getBearerToken(String accessToken) { @@ -556,7 +593,7 @@ public void write(Buffer source, long byteCount) throws IOException { * A listener interface that allows tracking byte writing. */ public interface ProgressListener { - void onRequestProgress(long bytesWritten, long contentLength) throws IOException; + void onRequestProgress(long bytesWritten, long contentLength); } /** diff --git a/cli/central-client/src/main/java/org/ballerinalang/central/client/exceptions/PackageAlreadyExistsException.java b/cli/central-client/src/main/java/org/ballerinalang/central/client/exceptions/PackageAlreadyExistsException.java index 07103eb3f773..bbe467e77b47 100644 --- a/cli/central-client/src/main/java/org/ballerinalang/central/client/exceptions/PackageAlreadyExistsException.java +++ b/cli/central-client/src/main/java/org/ballerinalang/central/client/exceptions/PackageAlreadyExistsException.java @@ -25,7 +25,14 @@ */ public class PackageAlreadyExistsException extends CentralClientException { - public PackageAlreadyExistsException(String message) { + private final String version; + + public PackageAlreadyExistsException(String message, String version) { super(message); + this.version = version; + } + + public String version() { + return version; } } diff --git a/cli/central-client/src/main/java/org/ballerinalang/central/client/model/PackageResolutionRequest.java b/cli/central-client/src/main/java/org/ballerinalang/central/client/model/PackageResolutionRequest.java index 8b1cd8ed6dd0..e8882fbca8da 100644 --- a/cli/central-client/src/main/java/org/ballerinalang/central/client/model/PackageResolutionRequest.java +++ b/cli/central-client/src/main/java/org/ballerinalang/central/client/model/PackageResolutionRequest.java @@ -25,7 +25,6 @@ import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; - import java.io.IOException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -154,18 +153,14 @@ public void write(final JsonWriter jsonWriter, @Nullable final String s) @Override @Nonnull - @SuppressWarnings("EnumSwitchStatementWhichMissesCases") public String read(final JsonReader jsonReader) throws IOException { final JsonToken token = jsonReader.peek(); - switch (token) { - case NULL: - return ""; - case STRING: - return jsonReader.nextString(); - default: - throw new IllegalStateException("Unexpected token: " + token); - } + return switch (token) { + case NULL -> ""; + case STRING -> jsonReader.nextString(); + default -> throw new IllegalStateException("Unexpected token: " + token); + }; } } diff --git a/cli/central-client/src/test/java/org/ballerinalang/central/client/TestCentralApiClient.java b/cli/central-client/src/test/java/org/ballerinalang/central/client/TestCentralApiClient.java index 48533f4ee53c..3450d1f985f4 100644 --- a/cli/central-client/src/test/java/org/ballerinalang/central/client/TestCentralApiClient.java +++ b/cli/central-client/src/test/java/org/ballerinalang/central/client/TestCentralApiClient.java @@ -39,6 +39,8 @@ import org.ballerinalang.central.client.model.ToolResolutionCentralRequest; import org.ballerinalang.central.client.model.ToolResolutionCentralResponse; import org.ballerinalang.central.client.model.ToolSearchResult; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -55,7 +57,6 @@ import java.net.HttpURLConnection; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; import static java.util.concurrent.TimeUnit.SECONDS; @@ -71,6 +72,8 @@ import static org.ballerinalang.central.client.CentralClientConstants.LOCATION; import static org.ballerinalang.central.client.TestUtils.cleanDirectory; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.CALLS_REAL_METHODS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -81,7 +84,8 @@ public class TestCentralApiClient extends CentralAPIClient { private ByteArrayOutputStream console; - private static final Path UTILS_TEST_RESOURCES = Paths.get("src/test/resources/test-resources/utils"); + public static final String ERROR_CONNECTION_RESET = "error: Connection reset"; + private static final Path UTILS_TEST_RESOURCES = Path.of("src/test/resources/test-resources/utils"); private static final Path TMP_DIR = UTILS_TEST_RESOURCES.resolve("temp-test-central-api-client"); private static final String TEST_BAL_VERSION = "slp5"; private static final String ANY_PLATFORM = "any"; @@ -96,7 +100,8 @@ public class TestCentralApiClient extends CentralAPIClient { private final OkHttpClient client = mock(OkHttpClient.class); public TestCentralApiClient() { - super("https://localhost:9090/registry", null, ACCESS_TOKEN); + super("https://localhost:9090/registry", null, ACCESS_TOKEN, true, 3, + System.out); } @Override @@ -430,7 +435,7 @@ public void testGetPackageWithBadGateway() throws IOException, CentralClientExce this.getPackage("bar", WINERY, "v2", ANY_PLATFORM, TEST_BAL_VERSION); } - + @Test(description = "Test get package versions") public void testGetPackageVersions() throws IOException, CentralClientException { Request mockRequest = new Request.Builder() @@ -447,20 +452,20 @@ public void testGetPackageVersions() throws IOException, CentralClientException "[\"2.3.4\", \"1.2.3\"]" )) .build(); - + when(this.remoteCall.execute()).thenReturn(mockResponse); when(this.client.newCall(any())).thenReturn(this.remoteCall); - + List versions = this.getPackageVersions("foo", WINERY, ANY_PLATFORM, TEST_BAL_VERSION); Assert.assertEquals(versions.size(), 2); Assert.assertEquals(versions.get(0), "2.3.4"); Assert.assertEquals(versions.get(1), "1.2.3"); } - + @Test(description = "Test get versions of non existing package") public void testGetNonExistingPackageVersions() throws IOException, CentralClientException { String resString = "{\"message\":\"package not found: ballerina/jballerina:*_any\"}"; - + Request mockRequest = new Request.Builder() .get() .url("https://localhost:9090/registry/packages/bar/" + WINERY) @@ -475,10 +480,10 @@ public void testGetNonExistingPackageVersions() throws IOException, CentralClien resString )) .build(); - + when(this.remoteCall.execute()).thenReturn(mockResponse); when(this.client.newCall(any())).thenReturn(this.remoteCall); - + List versions = this.getPackageVersions("bar", WINERY, ANY_PLATFORM, TEST_BAL_VERSION); Assert.assertEquals(versions.size(), 0); } @@ -644,7 +649,7 @@ public void testSearchPackageWithBadRequest() throws IOException, CentralClientE private void setBallerinaHome() { final String ballerinaInstallDirProp = "ballerina.home"; if (System.getProperty(ballerinaInstallDirProp) == null) { - System.setProperty(ballerinaInstallDirProp, String.valueOf(Paths.get("build"))); + System.setProperty(ballerinaInstallDirProp, String.valueOf(Path.of("build"))); } } @@ -870,14 +875,14 @@ public void testPullTool() throws IOException, CentralClientException { " \"name\": \"toolbox\",\n" + " \"version\": \"0.1.0\",\n" + " \"balaURL\": \"" + toolBalaUrl + "\",\n" + - " \"platform\": \"java17\"\n}"); + " \"platform\": \"java17\",\n" + + " \"digest\": \"sha-256=623bae28884bbc9cd61eb684acf7921cf43cb1d19ed0e36766bf6a75b0cdb15b\"\n}"); Response mockResponse = new Response.Builder() .request(mockRequest) .protocol(Protocol.HTTP_1_1) .code(HttpURLConnection.HTTP_OK) .addHeader(LOCATION, this.balaUrl) .addHeader(CONTENT_DISPOSITION, balaFileName) - .addHeader(DIGEST, "sha-256=47e043c80d516234b1e6bd93140f126c9d9e79b5c7c0600cc6316d12504c2cf4") .message("") .body(mockResponseBody) .build(); @@ -918,4 +923,277 @@ public void testPullTool() throws IOException, CentralClientException { cleanTmpDir(); } } + + @Test(description = "Test pull package with lower connection reset than retries") + public void testPullPackageConnectionReset1() throws CentralClientException, IOException { + String retryOutput = "* Retrying to pull the package: foo/sf:1.3.5 due to: error" + + ": Connection reset. Retry attempt: "; + Path balaPath = UTILS_TEST_RESOURCES.resolve(TEST_BALA_NAME); + File balaFile = new File(String.valueOf(balaPath)); + String balaFileName = "attachment; filename=sf-2020r2-any-1.3.5.bala"; + try (InputStream ignored = new FileInputStream(balaFile)) { + Request mockRequest = new Request.Builder() + .get() + .url("https://localhost:9090/registry/packages/foo/sf/1.3.5") + .addHeader(ACCEPT_ENCODING, IDENTITY) + .addHeader(ACCEPT, APPLICATION_OCTET_STREAM) + .build(); + Response mockResponse = new Response.Builder() + .request(mockRequest) + .protocol(Protocol.HTTP_1_1) + .code(HttpURLConnection.HTTP_MOVED_TEMP) + .addHeader(LOCATION, this.balaUrl) + .addHeader(CONTENT_DISPOSITION, balaFileName) + .message("") + .body(null) + .build(); + Request mockDownloadBalaRequest = new Request.Builder() + .get() + .url(this.balaUrl) + .header(ACCEPT_ENCODING, IDENTITY) + .addHeader(CONTENT_DISPOSITION, balaFileName) + .build(); + Response mockDownloadBalaResponse = new Response.Builder() + .request(mockDownloadBalaRequest) + .protocol(Protocol.HTTP_1_1) + .code(HttpURLConnection.HTTP_OK) + .message("") + .body(ResponseBody.create( + MediaType.get(APPLICATION_OCTET_STREAM), + Files.readAllBytes(balaPath) + )) + .build(); + try (MockedStatic utils = Mockito.mockStatic(Utils.class, CALLS_REAL_METHODS)) { + utils.when(() -> Utils.writeBalaFile(any(), any(), any(), + anyLong(), any(), any(), any(), any())) + .thenThrow(new CentralClientException(ERROR_CONNECTION_RESET)) + .thenThrow(new CentralClientException(ERROR_CONNECTION_RESET)) + .thenCallRealMethod(); + when(this.remoteCall.execute()).thenReturn(mockResponse, mockDownloadBalaResponse, + mockResponse, mockDownloadBalaResponse, mockResponse, mockDownloadBalaResponse, + mockResponse, mockDownloadBalaResponse); + when(this.client.newCall(any())).thenReturn(this.remoteCall); + System.setProperty(CentralClientConstants.ENABLE_OUTPUT_STREAM, "true"); + this.pullPackage("foo", "sf", "1.3.5", TMP_DIR, ANY_PLATFORM, TEST_BAL_VERSION, false); + String buildLog = readOutput(); + Assert.assertTrue(buildLog.contains(retryOutput + "1")); + Assert.assertTrue(buildLog.contains(retryOutput + "2")); + Assert.assertFalse(buildLog.contains(retryOutput + "3")); + Assert.assertTrue(buildLog.contains("foo/sf:1.3.5 pulled from central successfully")); + } + } finally { + cleanTmpDir(); + } + } + + @Test(description = "Test pull package with higher connection reset than retries") + public void testPullPackageConnectionReset2() throws IOException { + String retryOutput = "* Retrying to pull the package: foo/sf:1.3.5 due to: error" + + ": Connection reset. Retry attempt: "; + Path balaPath = UTILS_TEST_RESOURCES.resolve(TEST_BALA_NAME); + File balaFile = new File(String.valueOf(balaPath)); + String balaFileName = "attachment; filename=sf-2020r2-any-1.3.5.bala"; + try (InputStream ignored = new FileInputStream(balaFile)) { + Request mockRequest = new Request.Builder() + .get() + .url("https://localhost:9090/registry/packages/foo/sf/1.3.5") + .addHeader(ACCEPT_ENCODING, IDENTITY) + .addHeader(ACCEPT, APPLICATION_OCTET_STREAM) + .build(); + Response mockResponse = new Response.Builder() + .request(mockRequest) + .protocol(Protocol.HTTP_1_1) + .code(HttpURLConnection.HTTP_MOVED_TEMP) + .addHeader(LOCATION, this.balaUrl) + .addHeader(CONTENT_DISPOSITION, balaFileName) + .message("") + .body(null) + .build(); + Request mockDownloadBalaRequest = new Request.Builder() + .get() + .url(this.balaUrl) + .header(ACCEPT_ENCODING, IDENTITY) + .addHeader(CONTENT_DISPOSITION, balaFileName) + .build(); + Response mockDownloadBalaResponse = new Response.Builder() + .request(mockDownloadBalaRequest) + .protocol(Protocol.HTTP_1_1) + .code(HttpURLConnection.HTTP_OK) + .message("") + .body(ResponseBody.create( + MediaType.get(APPLICATION_OCTET_STREAM), + Files.readAllBytes(balaPath) + )) + .build(); + try (MockedStatic utils = Mockito.mockStatic(Utils.class, CALLS_REAL_METHODS)) { + utils.when(() -> Utils.writeBalaFile(any(), any(), any(), + anyLong(), any(), any(), any(), any())) + .thenThrow(new CentralClientException(ERROR_CONNECTION_RESET)) + .thenThrow(new CentralClientException(ERROR_CONNECTION_RESET)) + .thenThrow(new CentralClientException(ERROR_CONNECTION_RESET)) + .thenThrow(new CentralClientException(ERROR_CONNECTION_RESET)) + .thenCallRealMethod(); + when(this.remoteCall.execute()).thenReturn(mockResponse, mockDownloadBalaResponse, + mockResponse, mockDownloadBalaResponse, mockResponse, mockDownloadBalaResponse, + mockResponse, mockDownloadBalaResponse, mockResponse, mockDownloadBalaResponse); + when(this.client.newCall(any())).thenReturn(this.remoteCall); + + System.setProperty(CentralClientConstants.ENABLE_OUTPUT_STREAM, "true"); + this.pullPackage("foo", "sf", "1.3.5", TMP_DIR, ANY_PLATFORM, TEST_BAL_VERSION, false); + } catch (CentralClientException centralClientException) { + Assert.assertTrue(centralClientException.getMessage().contains("Connection reset")); + String buildLog = readOutput(); + Assert.assertTrue(buildLog.contains(retryOutput + "1")); + Assert.assertTrue(buildLog.contains(retryOutput + "2")); + Assert.assertTrue(buildLog.contains(retryOutput + "3")); + Assert.assertFalse(buildLog.contains(retryOutput + "4")); + Assert.assertFalse(buildLog.contains("foo/sf:1.3.5 pulled from central successfully")); + } + } finally { + cleanTmpDir(); + } + } + + @Test(description = "Test pull tool with lower connection reset than retries") + public void testPullToolConnectionReset1() throws CentralClientException, IOException { + String retryOutput = "* Retrying to pull the tool: foosf:1.3.5 due to: error" + + ": Connection reset. Retry attempt: "; + String responseBody = "{\"id\":14069, \"organization\":\"foo\", \"name\":\"sf\", \"version\":\"1.3.5\", " + + "\"platform\":\"java17\", \"balaURL\":\"" + this.balaUrl + "\", " + + "\"digest\":\"sha-256=47e043c80d516234b1e6bd93140f126c9d9e79b5c7c0600cc6316d12504c2cf4\"}"; + Path balaPath = UTILS_TEST_RESOURCES.resolve(TEST_BALA_NAME); + File balaFile = new File(String.valueOf(balaPath)); + String balaFileName = "attachment; filename=sf-2020r2-any-1.3.5.bala"; + try (InputStream ignored = new FileInputStream(balaFile)) { + Request mockRequest = new Request.Builder() + .get() + .url("https://localhost:9090/registry/tools/foosf/1.3.5") + .addHeader(ACCEPT_ENCODING, IDENTITY) + .addHeader(ACCEPT, APPLICATION_OCTET_STREAM) + .build(); + Response.Builder mockResponse = new Response.Builder() + .request(mockRequest) + .protocol(Protocol.HTTP_1_1) + .code(HttpURLConnection.HTTP_OK) + .addHeader(LOCATION, this.balaUrl) + .addHeader(CONTENT_DISPOSITION, balaFileName) + .message(""); + Request mockDownloadBalaRequest = new Request.Builder() + .get() + .url(this.balaUrl) + .header(ACCEPT_ENCODING, IDENTITY) + .addHeader(CONTENT_DISPOSITION, balaFileName) + .build(); + Response mockDownloadBalaResponse = new Response.Builder() + .request(mockDownloadBalaRequest) + .protocol(Protocol.HTTP_1_1) + .code(HttpURLConnection.HTTP_OK) + .message("") + .body(ResponseBody.create( + MediaType.get(APPLICATION_OCTET_STREAM), + Files.readAllBytes(balaPath) + )) + .build(); + try (MockedStatic utils = Mockito.mockStatic(Utils.class, CALLS_REAL_METHODS)) { + utils.when(() -> Utils.writeBalaFile(any(), any(), any(), + anyLong(), any(), any(), any(), any())) + .thenThrow(new CentralClientException(ERROR_CONNECTION_RESET)) + .thenThrow(new CentralClientException(ERROR_CONNECTION_RESET)) + .thenCallRealMethod(); + when(this.remoteCall.execute()).thenReturn(mockResponse.body(ResponseBody.create( + MediaType.get(APPLICATION_JSON), responseBody)).build(), mockDownloadBalaResponse, + mockResponse.body(ResponseBody.create(MediaType.get(APPLICATION_JSON), responseBody)).build(), + mockDownloadBalaResponse, mockResponse.body(ResponseBody.create(MediaType.get(APPLICATION_JSON), + responseBody)).build(), mockDownloadBalaResponse, + mockResponse.body(ResponseBody.create(MediaType.get(APPLICATION_JSON), + responseBody)).build(), mockDownloadBalaResponse); + when(this.client.newCall(any())).thenReturn(this.remoteCall); + System.setProperty(CentralClientConstants.ENABLE_OUTPUT_STREAM, "true"); + this.pullTool("foosf", "1.3.5", TMP_DIR, ANY_PLATFORM, TEST_BAL_VERSION, false); + String buildLog = readOutput(); + Assert.assertTrue(buildLog.contains(retryOutput + "1")); + Assert.assertTrue(buildLog.contains(retryOutput + "2")); + Assert.assertFalse(buildLog.contains(retryOutput + "3")); + Assert.assertTrue(buildLog.contains("foo/sf:1.3.5 pulled from central successfully")); + } + } finally { + cleanTmpDir(); + } + } + + @Test(description = "Test pull tool with higher connection reset than retries") + public void testPullToolConnectionReset2() throws IOException { + String retryOutput = "* Retrying to pull the tool: foosf:1.3.5 due to: error" + + ": Connection reset. Retry attempt: "; + String responseBody = "{\"id\":14069, \"organization\":\"foo\", \"name\":\"sf\", \"version\":\"1.3.5\", " + + "\"platform\":\"java17\", \"balaURL\":\"" + this.balaUrl + "\", " + + "\"digest\":\"sha-256=47e043c80d516234b1e6bd93140f126c9d9e79b5c7c0600cc6316d12504c2cf4\"}"; + Path balaPath = UTILS_TEST_RESOURCES.resolve(TEST_BALA_NAME); + File balaFile = new File(String.valueOf(balaPath)); + String balaFileName = "attachment; filename=sf-2020r2-any-1.3.5.bala"; + try (InputStream ignored = new FileInputStream(balaFile)) { + Request mockRequest = new Request.Builder() + .get() + .url("https://localhost:9090/registry/tools/foosf/1.3.5") + .addHeader(ACCEPT_ENCODING, IDENTITY) + .addHeader(ACCEPT, APPLICATION_OCTET_STREAM) + .build(); + Response.Builder mockResponse = new Response.Builder() + .request(mockRequest) + .protocol(Protocol.HTTP_1_1) + .code(HttpURLConnection.HTTP_OK) + .addHeader(LOCATION, this.balaUrl) + .addHeader(CONTENT_DISPOSITION, balaFileName) + .message(""); + Request mockDownloadBalaRequest = new Request.Builder() + .get() + .url(this.balaUrl) + .header(ACCEPT_ENCODING, IDENTITY) + .addHeader(CONTENT_DISPOSITION, balaFileName) + .build(); + Response mockDownloadBalaResponse = new Response.Builder() + .request(mockDownloadBalaRequest) + .protocol(Protocol.HTTP_1_1) + .code(HttpURLConnection.HTTP_OK) + .message("") + .body(ResponseBody.create( + MediaType.get(APPLICATION_OCTET_STREAM), + Files.readAllBytes(balaPath) + )) + .build(); + try (MockedStatic utils = Mockito.mockStatic(Utils.class, CALLS_REAL_METHODS)) { + utils.when(() -> Utils.writeBalaFile(any(), any(), any(), + anyLong(), any(), any(), any(), any())) + .thenThrow(new CentralClientException(ERROR_CONNECTION_RESET)) + .thenThrow(new CentralClientException(ERROR_CONNECTION_RESET)) + .thenThrow(new CentralClientException(ERROR_CONNECTION_RESET)) + .thenThrow(new CentralClientException(ERROR_CONNECTION_RESET)) + .thenCallRealMethod(); + when(this.remoteCall.execute()).thenReturn(mockResponse.body(ResponseBody.create( + MediaType.get(APPLICATION_JSON), responseBody)).build(), mockDownloadBalaResponse, + mockResponse.body(ResponseBody.create( + MediaType.get(APPLICATION_JSON), responseBody)).build(), mockDownloadBalaResponse, + mockResponse.body(ResponseBody.create( + MediaType.get(APPLICATION_JSON), responseBody)).build(), mockDownloadBalaResponse, + mockResponse.body(ResponseBody.create( + MediaType.get(APPLICATION_JSON), responseBody)).build(), mockDownloadBalaResponse, + mockResponse.body(ResponseBody.create( + MediaType.get(APPLICATION_JSON), responseBody)).build(), mockDownloadBalaResponse); + when(this.client.newCall(any())).thenReturn(this.remoteCall); + + System.setProperty(CentralClientConstants.ENABLE_OUTPUT_STREAM, "true"); + this.pullTool("foosf", "1.3.5", TMP_DIR, ANY_PLATFORM, TEST_BAL_VERSION, false); + } catch (CentralClientException centralClientException) { + Assert.assertTrue(centralClientException.getMessage().contains("Connection reset")); + String buildLog = readOutput(); + Assert.assertTrue(buildLog.contains(retryOutput + "1")); + Assert.assertTrue(buildLog.contains(retryOutput + "2")); + Assert.assertTrue(buildLog.contains(retryOutput + "3")); + Assert.assertFalse(buildLog.contains(retryOutput + "4")); + Assert.assertFalse(buildLog.contains("foo/sf:1.3.5 pulled from central successfully")); + } + } finally { + cleanTmpDir(); + } + } } diff --git a/cli/central-client/src/test/java/org/ballerinalang/central/client/TestCustomRetryInterceptor.java b/cli/central-client/src/test/java/org/ballerinalang/central/client/TestCustomRetryInterceptor.java new file mode 100644 index 000000000000..54dadc4d9526 --- /dev/null +++ b/cli/central-client/src/test/java/org/ballerinalang/central/client/TestCustomRetryInterceptor.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (https://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 org.ballerinalang.central.client; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.net.HttpURLConnection; +import java.util.Locale; + +/** + * Test cases to test retry logic. + */ + +public class TestCustomRetryInterceptor { + public static final String BASE_PATH = "/"; + private static final Boolean isWindows = System.getProperty("os.name").toLowerCase(Locale.getDefault()) + .contains("win"); + public static final int PORT = 57803; + private MockWebServer mockWebServer; + private OkHttpClient centralHttpClient; + private static final String ACCESS_TOKEN = "273cc9f6-c333-36ab-aa2q-f08e9513ff5y"; + private ByteArrayOutputStream console; + + + @BeforeClass + public void setUp() { + this.console = new ByteArrayOutputStream(); + PrintStream outStream = new PrintStream(this.console); + CentralAPIClient centralAPIClient = new CentralAPIClient("https://localhost:9090/registry", + null, ACCESS_TOKEN, true, 3, outStream); + centralHttpClient = centralAPIClient.getClient(); + } + + private String readOutput() { + String output; + output = this.console.toString(); + this.console.reset(); + return output; + } + + @Test(description = "Return failure response all the time.") + public void testRetries() throws IOException { + String expectedOutputPrefix = "* Retrying request to http://localhost:57803/ " + + "due to 500 response code. Retry attempt: "; + mockWebServer = new MockWebServer(); + mockWebServer.start(PORT); + mockWebServer.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_INTERNAL_ERROR)); + mockWebServer.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_INTERNAL_ERROR)); + mockWebServer.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_INTERNAL_ERROR)); + mockWebServer.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_INTERNAL_ERROR)); + Request request = new Request.Builder() + .url(mockWebServer.url(BASE_PATH)) + .build(); + Response response = centralHttpClient.newCall(request).execute(); + String consoleOutput = readOutput(); + if (isWindows) { + consoleOutput = consoleOutput.replaceAll(mockWebServer.url(BASE_PATH).host(), "localhost"); + } + Assert.assertEquals(response.code(), HttpURLConnection.HTTP_INTERNAL_ERROR); + Assert.assertTrue(consoleOutput.contains(expectedOutputPrefix + 1), consoleOutput); + Assert.assertTrue(consoleOutput.contains(expectedOutputPrefix + 2), consoleOutput); + Assert.assertTrue(consoleOutput.contains(expectedOutputPrefix + 3), consoleOutput); + Assert.assertFalse(consoleOutput.contains(expectedOutputPrefix + 4), consoleOutput); + mockWebServer.close(); + } + + @Test(description = "Return successful response before retry maximum is reached.", dependsOnMethods = "testRetries") + public void testRetries2() throws IOException { + String expectedOutputPrefix = "* Retrying request to http://localhost:57804/ " + + "due to 502 response code. Retry attempt: "; + mockWebServer = new MockWebServer(); + mockWebServer.start(PORT + 1); + mockWebServer.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_BAD_GATEWAY)); + mockWebServer.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_BAD_GATEWAY)); + mockWebServer.enqueue(new MockResponse().setResponseCode(HttpURLConnection.HTTP_OK)); + + Request request = new Request.Builder() + .url(mockWebServer.url(BASE_PATH)) + .build(); + Response response = centralHttpClient.newCall(request).execute(); + String consoleOutput = readOutput(); + if (isWindows) { + consoleOutput = consoleOutput.replaceAll(mockWebServer.url(BASE_PATH).host(), "localhost"); + } + Assert.assertEquals(response.code(), HttpURLConnection.HTTP_OK); + Assert.assertTrue(consoleOutput.contains(expectedOutputPrefix + 1), consoleOutput); + Assert.assertTrue(consoleOutput.contains(expectedOutputPrefix + 2), consoleOutput); + Assert.assertFalse(consoleOutput.contains(expectedOutputPrefix + 3), consoleOutput); + mockWebServer.close(); + } +} diff --git a/cli/central-client/src/test/java/org/ballerinalang/central/client/TestUtils.java b/cli/central-client/src/test/java/org/ballerinalang/central/client/TestUtils.java index 537b34dedef1..2b74d4f81435 100644 --- a/cli/central-client/src/test/java/org/ballerinalang/central/client/TestUtils.java +++ b/cli/central-client/src/test/java/org/ballerinalang/central/client/TestUtils.java @@ -30,19 +30,17 @@ import org.testng.annotations.Test; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; import java.net.HttpURLConnection; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; +import java.util.stream.Stream; import static org.ballerinalang.central.client.CentralClientConstants.ACCEPT; import static org.ballerinalang.central.client.CentralClientConstants.ACCEPT_ENCODING; @@ -59,8 +57,8 @@ */ public class TestUtils { - private static final Path UTILS_TEST_RESOURCES = Paths.get("src/test/resources/test-resources/utils"); - private final Path tempBalaCache = Paths.get("build").resolve("temp-test-utils-bala-cache"); + private static final Path UTILS_TEST_RESOURCES = Path.of("src/test/resources/test-resources/utils"); + private final Path tempBalaCache = Path.of("build").resolve("temp-test-utils-bala-cache"); @BeforeClass public void setUp() throws IOException { @@ -106,8 +104,6 @@ public void testGetAsList(String versionList, List expectedArray) { public void testWriteBalaFile() throws IOException, CentralClientException { final String balaName = "sf-any.bala"; Path balaFile = UTILS_TEST_RESOURCES.resolve(balaName); - File initialFile = new File(String.valueOf(balaFile)); - InputStream targetStream = new FileInputStream(initialFile); Request mockRequest = new Request.Builder() .get() @@ -158,8 +154,6 @@ public void testValidatePackageVersion(String version, boolean isValid) throws C public void testCreateBalaInHomeRepo() throws IOException, CentralClientException { final String balaName = "sf-any.bala"; Path balaFile = UTILS_TEST_RESOURCES.resolve(balaName); - File initialFile = new File(String.valueOf(balaFile)); - InputStream targetStream = new FileInputStream(initialFile); Request mockRequest = new Request.Builder() .get() @@ -191,8 +185,6 @@ public void testCreateBalaInHomeRepo() throws IOException, CentralClientExceptio public void testCreateBalaInHomeRepoWhenBalaExists() throws IOException { final String balaName = "sf-any.bala"; Path balaFile = UTILS_TEST_RESOURCES.resolve(balaName); - File initialFile = new File(String.valueOf(balaFile)); - InputStream targetStream = new FileInputStream(initialFile); Request mockRequest = new Request.Builder() .get() @@ -235,9 +227,8 @@ private void cleanBalaCache() { } static void cleanDirectory(Path path) { - try { - Files.walk(path) - .sorted(Comparator.reverseOrder()) + try (Stream paths = Files.walk(path)) { + paths.sorted(Comparator.reverseOrder()) .map(Path::toFile) .filter(item -> !item.getPath().equals(path.toString())) .forEach(File::delete); diff --git a/compiler/ballerina-lang/build.gradle b/compiler/ballerina-lang/build.gradle index 28cf03d88f29..55f8b87b71ca 100644 --- a/compiler/ballerina-lang/build.gradle +++ b/compiler/ballerina-lang/build.gradle @@ -14,8 +14,10 @@ * limitations under the License. * */ - -apply from: "$rootDir/gradle/javaProject.gradle" + +plugins { + id 'javaProject' +} dependencies { implementation project(':ballerina-tools-api') @@ -25,19 +27,22 @@ dependencies { implementation project(':central-client') implementation project(':maven-resolver') implementation project(':identifier-util') - implementation 'com.moandjiezana.toml:toml4j' - implementation "org.apache.commons:commons-compress:${project.apacheCommonsCompressVersion}" - implementation 'io.netty:netty-buffer' - implementation 'org.ow2.asm:asm' - implementation 'commons-io:commons-io' - implementation 'com.github.zafarkhaja:java-semver' - testImplementation ("guru.nidi:graphviz-java") { + implementation libs.toml4j + implementation(libs.apache.commons.compress) { + exclude group: 'commons-codec', module: 'commons-codec' + exclude group: 'org.apache.commons', module: 'commons-lang3' + } + implementation libs.netty.buffer + implementation libs.ow2.asm + implementation libs.commons.io + implementation libs.zafarkhaja.jsemver + testImplementation(libs.guru.nidi.graphviz) { because("We use this library to execute package resolution tests") } - testImplementation "org.testng:testng:${project.testngVersion}" - testImplementation "org.mockito:mockito-core:${project.mockitoCoreVersion}" - testImplementation "org.mockito:mockito-testng:${project.mockitoTestNGVersion}" - testImplementation 'org.apache.commons:commons-lang3' + testImplementation libs.testng + testImplementation libs.mockito.core + testImplementation libs.mockito.testng + testImplementation libs.apache.commons.lang3 } description = 'Ballerina - Lang' @@ -85,9 +90,14 @@ ext.moduleName = 'ballerina.lang' compileJava { inputs.property("moduleName", moduleName) doFirst { - options.compilerArgs = [ - '--module-path', classpath.asPath, - ] + options.compilerArgs << '--module-path' << classpath.asPath + classpath = files() + } +} + +javadoc { + doFirst { + options.modulePath = classpath.toList() classpath = files() } } diff --git a/compiler/ballerina-lang/spotbugs-exclude.xml b/compiler/ballerina-lang/spotbugs-exclude.xml index 5dd4391030ca..601166b8aaff 100644 --- a/compiler/ballerina-lang/spotbugs-exclude.xml +++ b/compiler/ballerina-lang/spotbugs-exclude.xml @@ -32,6 +32,9 @@ + + + @@ -420,6 +423,11 @@ + + + + + diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BallerinaKeywordsProvider.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BallerinaKeywordsProvider.java index e512173f4b23..27bdb6383148 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BallerinaKeywordsProvider.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BallerinaKeywordsProvider.java @@ -20,20 +20,23 @@ import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.stream.Collectors; /** * Provides the set of Ballerina Reserved Keywords to be used at the symbol factory. * * @since 2.0.0 */ -public class BallerinaKeywordsProvider { +public final class BallerinaKeywordsProvider { + public static final List BALLERINA_KEYWORDS; static { BALLERINA_KEYWORDS = getBallerinaKeywords(); } + private BallerinaKeywordsProvider() { + } + private static List getBallerinaKeywords() { // NOTE: This is a temporary fix to retrieve lexer defined keywords until we come up with an appropriate API. // The same implementation can be found in the language server common utils. @@ -51,7 +54,7 @@ private static List getBallerinaKeywords() { } }) .filter(Objects::nonNull) - .collect(Collectors.toList()); + .toList(); } catch (ClassNotFoundException e) { return Collections.emptyList(); } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BallerinaModuleID.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BallerinaModuleID.java index 7d0dc68341c5..e7aef19af46c 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BallerinaModuleID.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BallerinaModuleID.java @@ -32,7 +32,7 @@ public class BallerinaModuleID implements ModuleID { private static final String ANON_ORG = "$anon"; - private PackageID moduleID; + private final PackageID moduleID; private Name prefix; public BallerinaModuleID(PackageID moduleID) { diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BallerinaSemanticModel.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BallerinaSemanticModel.java index 41650e96b605..73bf9e881f9b 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BallerinaSemanticModel.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BallerinaSemanticModel.java @@ -688,15 +688,16 @@ private boolean isIgnorableSelfSymbol(Name name, BSymbol symbol, BSymbol symbolE } private boolean isFilteredVarSymbol(BSymbol symbol, Set states) { - return symbol instanceof BVarSymbol && !states.contains(((BVarSymbol) symbol).state); + return symbol instanceof BVarSymbol varSymbol && !states.contains(varSymbol.state); } private boolean isObjectConstructorExpr(BLangNode node) { - return node instanceof BLangClassDefinition && ((BLangClassDefinition) node).flagSet.contains(Flag.OBJECT_CTOR); + return node instanceof BLangClassDefinition classDefinition && + classDefinition.flagSet.contains(Flag.OBJECT_CTOR); } private boolean isAnonFunctionExpr(BLangNode node) { - return (node instanceof BLangFunction && ((BLangFunction) node).flagSet.contains(Flag.LAMBDA)) + return (node instanceof BLangFunction bLangFunction && bLangFunction.flagSet.contains(Flag.LAMBDA)) || node instanceof BLangArrowFunction; } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BaseVisitor.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BaseVisitor.java index 212dca7bf91b..0c6a541c9c0c 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BaseVisitor.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/BaseVisitor.java @@ -143,6 +143,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementFilter; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -607,7 +610,7 @@ public void visit(BLangFieldBasedAccess fieldAccessExpr) { } @Override - public void visit(BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess nsPrefixedFieldBasedAccess) { + public void visit(BLangFieldBasedAccess.BLangPrefixedFieldBasedAccess prefixedFieldBasedAccess) { } @Override @@ -910,10 +913,6 @@ public void visit(BLangRecordLiteral.BLangMapLiteral mapLiteral) { public void visit(BLangRecordLiteral.BLangStructLiteral structLiteral) { } - @Override - public void visit(BLangRecordLiteral.BLangChannelLiteral channelLiteral) { - } - @Override public void visit(BLangInvocation.BFunctionPointerInvocation bFunctionPointerInvocation) { } @@ -1046,10 +1045,23 @@ public void visit(BLangXMLElementAccess xmlElementAccess) { public void visit(BLangXMLNavigationAccess xmlNavigation) { } + @Override + public void visit(BLangXMLIndexedStepExtend xmlIndexedStepExtend) { + } + + @Override + public void visit(BLangXMLFilterStepExtend xmlFilterStepExtend) { + } + + @Override + public void visit(BLangXMLMethodCallStepExtend xmlMethodCallStepExtend) { + } + @Override public void visit(BLangClassDefinition classDefinition) { } + @Override public abstract void visit(BLangInvocation.BLangResourceAccessInvocation resourceAccessInvocation); @Override diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/EnvironmentResolver.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/EnvironmentResolver.java index 2beefafb0c25..a39cc3746b01 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/EnvironmentResolver.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/EnvironmentResolver.java @@ -603,7 +603,7 @@ public void visit(BLangJoinClause joinClause) { } this.scope = joinClause.env; this.acceptNode(joinClause.collection, joinClause.env); - this.acceptNode((BLangNode) joinClause.onClause, joinClause.env); + this.acceptNode(joinClause.onClause, joinClause.env); } @Override diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/ExpectedTypeFinder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/ExpectedTypeFinder.java index 43152997caea..c19429826ce3 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/ExpectedTypeFinder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/ExpectedTypeFinder.java @@ -132,7 +132,6 @@ import java.util.Objects; import java.util.Optional; import java.util.function.Predicate; -import java.util.stream.Collectors; import static io.ballerina.compiler.api.impl.PositionUtil.isPosWithinOpenCloseLineRanges; import static io.ballerina.compiler.api.impl.PositionUtil.isPosWithinRange; @@ -227,9 +226,7 @@ public Optional transform(SpecificFieldNode node) { return Optional.empty(); } - if (bLangNode instanceof BLangRecordLiteral.BLangRecordVarNameField) { - BLangRecordLiteral.BLangRecordVarNameField bLangNodeRecLiteral = - (BLangRecordLiteral.BLangRecordVarNameField) bLangNode; + if (bLangNode instanceof BLangRecordLiteral.BLangRecordVarNameField bLangNodeRecLiteral) { if (bLangNodeRecLiteral.symbol != null && node.parent().kind() == SyntaxKind.MAPPING_CONSTRUCTOR) { BLangExpression bLangExpression = bLangNodeRecLiteral.impConversionExpr; if (bLangExpression != null && bLangExpression.getBType().getKind() == TypeKind.ANY) { @@ -306,11 +303,10 @@ public Optional transform(BinaryExpressionNode node) { } BLangNode bLangNode = nodeFinder.lookup(this.bLangCompilationUnit, node.lineRange()); - if (!(bLangNode instanceof BLangBinaryExpr)) { + if (!(bLangNode instanceof BLangBinaryExpr bLangBinaryExpr)) { return Optional.empty(); } - BLangBinaryExpr bLangBinaryExpr = (BLangBinaryExpr) bLangNode; BLangExpression rhs = bLangBinaryExpr.rhsExpr; BLangExpression lhs = bLangBinaryExpr.lhsExpr; BType rhsExpType = rhs.expectedType; @@ -330,7 +326,7 @@ public Optional transform(FunctionCallExpressionNode node) { return Optional.empty(); } - return (bLangInvocation.symbol instanceof BInvokableSymbol && bLangInvocation.getRequiredArgs().size() > 0) ? + return (bLangInvocation.symbol instanceof BInvokableSymbol && !bLangInvocation.getRequiredArgs().isEmpty()) ? transformFunctionOrMethod(bLangNode, ((BLangNode) bLangInvocation.getRequiredArgs().get(0)).getBType(), (BInvokableSymbol) bLangInvocation.symbol, node.arguments(), @@ -367,12 +363,12 @@ public Optional transform(QualifiedNameReferenceNode node) { return Optional.empty(); } - if (bLangNode instanceof BLangSimpleVarRef && ((BLangSimpleVarRef) bLangNode).symbol != null) { - return getTypeFromBType(((BLangSimpleVarRef) bLangNode).symbol.getType()); + if (bLangNode instanceof BLangSimpleVarRef simpleVarRef && ((BLangSimpleVarRef) bLangNode).symbol != null) { + return getTypeFromBType(simpleVarRef.symbol.getType()); } - if (bLangNode instanceof BLangUserDefinedType && ((BLangUserDefinedType) bLangNode).symbol != null) { - return getTypeFromBType(((BLangUserDefinedType) bLangNode).symbol.getType()); + if (bLangNode instanceof BLangUserDefinedType userDefinedType && userDefinedType.symbol != null) { + return getTypeFromBType(userDefinedType.symbol.getType()); } return Optional.empty(); @@ -393,14 +389,14 @@ public Optional transform(ExplicitAnonymousFunctionExpressionNode no @Override public Optional transform(ImplicitAnonymousFunctionExpressionNode node) { BLangNode bLangNode = nodeFinder.lookup(this.bLangCompilationUnit, node.lineRange()); - if (!(bLangNode instanceof BLangArrowFunction)) { + if (!(bLangNode instanceof BLangArrowFunction arrowFunction)) { return Optional.empty(); } if (!node.rightDoubleArrow().isMissing() && node.rightDoubleArrow().lineRange().endLine().offset() <= linePosition.offset()) { // Cursor is at the expression node. - BType funcType = ((BLangArrowFunction) bLangNode).funcType; + BType funcType = arrowFunction.funcType; if (funcType == null) { return Optional.empty(); } @@ -444,10 +440,12 @@ public Optional transform(FunctionDefinitionNode node) { return ((FunctionSymbol) functionSymbol.get()).typeDescriptor().returnTypeDescriptor(); } + @Override public Optional transform(MatchClauseNode node) { return node.parent().apply(this); } + @Override public Optional transform(MatchStatementNode node) { return this.semanticModel.typeOf(node.condition()); } @@ -475,7 +473,7 @@ public Optional transform(ExplicitNewExpressionNode node) { instanceof BInvokableSymbol)) { List params = ((BInvokableSymbol) (((BLangInvocation) ((BLangTypeInit) bLangNode). initInvocation).symbol)).params; - if (params.size() == 0) { + if (params.isEmpty()) { throw new IllegalStateException(); } @@ -514,16 +512,14 @@ public Optional transform(ImplicitNewExpressionNode node) { Token closeParen = parenthesizedArgList.get().closeParenToken(); // Check if the line position is within the parameter context. if (isWithinParenthesis(openParen, closeParen)) { - if (!(bLangNode instanceof BLangTypeInit)) { + if (!(bLangNode instanceof BLangTypeInit bLangTypeInit)) { return getExpectedType(bLangNode); } - BLangTypeInit bLangTypeInit = (BLangTypeInit) bLangNode; - if (!(bLangTypeInit.initInvocation instanceof BLangInvocation)) { + if (!(bLangTypeInit.initInvocation instanceof BLangInvocation initInvocation)) { return getExpectedType(bLangNode); } - BLangInvocation initInvocation = (BLangInvocation) bLangTypeInit.initInvocation; if (initInvocation.symbol == null) { throw new IllegalStateException(); } @@ -562,8 +558,8 @@ public Optional transform(IfElseStatementNode node) { } if (isPosWithinRange(linePosition, node.condition().lineRange()) && - bLangNode instanceof BLangIf) { - return getExpectedType(((BLangIf) bLangNode).expr); + bLangNode instanceof BLangIf bLangIf) { + return getExpectedType(bLangIf.expr); } return Optional.empty(); @@ -577,8 +573,8 @@ public Optional transform(WhileStatementNode node) { } if (isPosWithinRange(linePosition, node.condition().lineRange()) - && bLangNode instanceof BLangWhile) { - return getExpectedType(((BLangWhile) bLangNode).expr); + && bLangNode instanceof BLangWhile bLangWhile) { + return getExpectedType(bLangWhile.expr); } return Optional.empty(); @@ -620,7 +616,7 @@ public Optional transform(RemoteMethodCallActionNode node) { Token openParen = node.openParenToken(); Token closeParen = node.closeParenToken(); if (isWithinParenthesis(openParen, closeParen)) { - if (bLangActionInvocation.argExprs.size() == 0) { + if (bLangActionInvocation.argExprs.isEmpty()) { return getTypeFromBType(((BInvokableSymbol) bLangActionInvocation.symbol). getParameters().get(0).getType()); } @@ -697,11 +693,10 @@ public Optional transform(MappingConstructorExpressionNode node) { @Override public Optional transform(WaitActionNode node) { BLangNode bLangNode = nodeFinder.lookup(this.bLangCompilationUnit, node.lineRange()); - if (!(bLangNode instanceof BLangWaitExpr)) { + if (!(bLangNode instanceof BLangWaitExpr waitExpr)) { return Optional.empty(); } - BLangWaitExpr waitExpr = (BLangWaitExpr) bLangNode; for (BLangExpression bLangExpression : waitExpr.exprList) { if (isPosWithinRange(linePosition, bLangExpression.getPosition().lineRange())) { return getExpectedType(bLangExpression); @@ -748,22 +743,21 @@ public Optional transform(NamedArgumentNode node) { @Override public Optional transform(TableConstructorExpressionNode node) { BLangNode bLangNode = nodeFinder.lookup(this.bLangCompilationUnit, node.lineRange()); - if (!(bLangNode instanceof BLangTableConstructorExpr)) { + if (!(bLangNode instanceof BLangTableConstructorExpr bLangTableConstructorExpr)) { return Optional.empty(); } - BLangTableConstructorExpr bLangTableConstructorExpr = (BLangTableConstructorExpr) bLangNode; if (node.keySpecifier().isPresent() && isWithinParenthesis(node.keySpecifier().get().openParenToken(), node.keySpecifier().get().closeParenToken())) { BType expectedType = bLangTableConstructorExpr.expectedType; - if (expectedType instanceof BTableType) { + if (expectedType instanceof BTableType tableType) { return Optional.of(typesFactory.getTypeDescriptor(Objects. - requireNonNullElse(((BTableType) expectedType).constraint, expectedType))); + requireNonNullElse(tableType.constraint, expectedType))); } - if (expectedType instanceof BTypeReferenceType) { - BType referredType = ((BTypeReferenceType) expectedType).referredType; + if (expectedType instanceof BTypeReferenceType referenceType) { + BType referredType = referenceType.referredType; return Optional.of(typesFactory.getTypeDescriptor(Objects. requireNonNullElse(((BTableType) referredType).constraint, expectedType))); } @@ -795,11 +789,11 @@ public Optional transform(RecordFieldWithDefaultValueNode node) { @Override public Optional transform(SelectClauseNode node) { BLangNode bLangNode = nodeFinder.lookup(bLangCompilationUnit, node.lineRange()); - if (!(bLangNode instanceof BLangSelectClause)) { + if (!(bLangNode instanceof BLangSelectClause selectClause)) { return Optional.empty(); } - BType expectedType = ((BLangExpression) ((BLangSelectClause) bLangNode).getExpression()).expectedType; + BType expectedType = ((BLangExpression) selectClause.getExpression()).expectedType; return getTypeFromBType(expectedType); } @@ -874,10 +868,9 @@ public Optional transform(ClientResourceAccessActionNode clientResou Optional arguments = clientResourceAccessActionNode.arguments(); if (arguments.isPresent() && isWithinParenthesis(arguments.get().openParenToken(), arguments.get().closeParenToken())) { - if (!(bLangNode instanceof BLangInvocation)) { + if (!(bLangNode instanceof BLangInvocation bLangInvocation)) { return getExpectedType(bLangNode); } - BLangInvocation bLangInvocation = (BLangInvocation) bLangNode; if (bLangInvocation.symbol == null) { return Optional.empty(); } @@ -885,7 +878,7 @@ public Optional transform(ClientResourceAccessActionNode clientResou //`params` contains path params and path rest params as well. We need to skip those List params = symbol.params.stream().filter(param -> param.getKind() != SymbolKind.PATH_PARAMETER - && param.getKind() != SymbolKind.PATH_REST_PARAMETER).collect(Collectors.toList()); + && param.getKind() != SymbolKind.PATH_REST_PARAMETER).toList(); BVarSymbol restPram = ((BInvokableSymbol) bLangInvocation.symbol).restParam; TypeSymbol restParamMemberType = null; @@ -954,8 +947,8 @@ private Optional getExpectedType(BLangNode node) { bType = ((BLangRecordLiteral) node).expectedType; break; case SIMPLE_VARIABLE_REF: - if (node instanceof BLangRecordLiteral) { - BLangExpression bLangExpression = ((BLangRecordLiteral) node).impConversionExpr; + if (node instanceof BLangRecordLiteral recordLiteral) { + BLangExpression bLangExpression = recordLiteral.impConversionExpr; if (bLangExpression != null && bLangExpression.getBType().getKind() == TypeKind.ANY) { bType = bLangExpression.getBType(); break; @@ -1068,7 +1061,7 @@ private List getModuleSymbols(QualifiedNameReferenceNode qNameRef, Optional module = searchModuleForAlias(alias); return module.map(moduleSymbol -> moduleSymbol.allSymbols().stream() .filter(predicate) - .collect(Collectors.toList())) + .toList()) .orElseGet(ArrayList::new); } @@ -1235,7 +1228,7 @@ private Optional transformFunctionOrMethod(BLangNode bLangNode, BTyp SeparatedNodeList arguments, Token openParenToken, Token closeParenToken, boolean hasFirstArg) { - if (originalInvokable == null || originalInvokable.params.size() == 0) { + if (originalInvokable == null || originalInvokable.params.isEmpty()) { return getExpectedTypeFromFunction(bLangNode, openParenToken, closeParenToken); } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/LangLibFunctionBinder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/LangLibFunctionBinder.java index 2ae6843c3ade..1118cbb37226 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/LangLibFunctionBinder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/LangLibFunctionBinder.java @@ -31,7 +31,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; /** * A util class for creating type param resolved version of the lang lib functions. @@ -64,7 +63,7 @@ public LangLibFunctionBinder(CompilerContext context) { * @return The type param resolved lang lib function symbol */ public BInvokableSymbol cloneAndBind(BInvokableSymbol original, BType type, BType boundType) { - if (boundType == null || original.params.size() == 0) { + if (boundType == null || original.params.isEmpty()) { return original; } @@ -126,7 +125,7 @@ private BInvokableType duplicateType(BInvokableType original, List n List paramTypes = new ArrayList<>(); if (newParams.size() == original.paramTypes.size()) { - paramTypes.addAll(newParams.stream().map(BSymbol::getType).collect(Collectors.toList())); + paramTypes.addAll(newParams.stream().map(BSymbol::getType).toList()); } else { paramTypes.addAll(original.paramTypes); } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/LangLibrary.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/LangLibrary.java index 302ef304c309..98dd7af33a89 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/LangLibrary.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/LangLibrary.java @@ -149,32 +149,24 @@ private void populateMethodList(List list, Map TypeKind.INT.typeName(); + case ARRAY, TUPLE -> "array"; + case RECORD, MAP -> TypeKind.MAP.typeName(); + case FLOAT, + DECIMAL, + STRING, + BOOLEAN, + STREAM, + OBJECT, + ERROR, + FUTURE, + TYPEDESC, + XML, + TABLE, + REGEXP -> typeKind.typeName(); + default -> LANG_VALUE; + }; } private static void addLangLibMethods(String basicType, BPackageSymbol langLibModule, diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/NodeFinder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/NodeFinder.java index 317c9f50fb74..e9d5e5346fe3 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/NodeFinder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/NodeFinder.java @@ -87,6 +87,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangElvisExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIndexBasedAccess; @@ -144,6 +145,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementFilter; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -216,7 +220,7 @@ class NodeFinder extends BaseVisitor { private LineRange range; private BLangNode enclosingNode; private BLangNode enclosingContainer; - private boolean allowExprStmts; + private final boolean allowExprStmts; NodeFinder(boolean allowExprStmts) { this.allowExprStmts = allowExprStmts; @@ -500,7 +504,7 @@ public void visit(BLangFromClause fromClause) { public void visit(BLangJoinClause joinClause) { lookupNode(joinClause.collection); lookupNode((BLangNode) joinClause.variableDefinitionNode); - lookupNode((BLangNode) joinClause.onClause); + lookupNode(joinClause.onClause); } @Override @@ -639,7 +643,7 @@ public void visit(BLangRecordLiteral recordLiteral) { @Override public void visit(BLangTupleVarRef varRefExpr) { lookupNodes(varRefExpr.expressions); - lookupNode((BLangNode) varRefExpr.restParam); + lookupNode(varRefExpr.restParam); } @Override @@ -1283,10 +1287,31 @@ public void visit(BLangXMLElementAccess xmlElementAccess) { @Override public void visit(BLangXMLNavigationAccess xmlNavigation) { lookupNode(xmlNavigation.expr); - lookupNode(xmlNavigation.childIndex); lookupNodes(xmlNavigation.filters); } + @Override + public void visit(BLangExtendedXMLNavigationAccess extendedXmlNavigationAccess) { + lookupNode(extendedXmlNavigationAccess.stepExpr); + lookupNodes(extendedXmlNavigationAccess.extensions); + } + + @Override + public void visit(BLangXMLIndexedStepExtend xmlIndexedStepExtend) { + lookupNode(xmlIndexedStepExtend.indexExpr); + } + + @Override + public void visit(BLangXMLFilterStepExtend xmlFilterStepExtend) { + lookupNodes(xmlFilterStepExtend.filters); + setEnclosingNode(xmlFilterStepExtend, xmlFilterStepExtend.pos); + } + + @Override + public void visit(BLangXMLMethodCallStepExtend xmlMethodCallStepExtend) { + lookupNode(xmlMethodCallStepExtend.invocation); + } + @Override public void visit(BLangMatchStatement matchStatementNode) { lookupNode(matchStatementNode.expr); @@ -1583,9 +1608,8 @@ private boolean isClassForService(TopLevelNode node) { } private boolean isWithinNodeMetaData(TopLevelNode node) { - if (node instanceof AnnotatableNode) { - List nodes = - (List) ((AnnotatableNode) node).getAnnotationAttachments(); + if (node instanceof AnnotatableNode annotatableNode) { + List nodes = annotatableNode.getAnnotationAttachments(); for (AnnotationAttachmentNode annotAttachment : nodes) { if (PositionUtil.isRangeWithinNode(this.range, annotAttachment.getPosition())) { diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/PositionUtil.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/PositionUtil.java index e9772f33764c..a87e6f56eca8 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/PositionUtil.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/PositionUtil.java @@ -27,7 +27,10 @@ * * @since 2.0.0 */ -class PositionUtil { +final class PositionUtil { + + private PositionUtil() { + } static boolean withinBlock(LinePosition cursorPos, Location symbolPosition) { if (symbolPosition == null) { diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/ReferenceFinder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/ReferenceFinder.java index 51d90433c385..c1d1b313f4d5 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/ReferenceFinder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/ReferenceFinder.java @@ -94,8 +94,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; import org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; -import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess.BLangPrefixedFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIndexBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangInvocation; @@ -151,6 +152,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementFilter; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -213,7 +217,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; import static org.ballerinalang.model.symbols.SymbolOrigin.VIRTUAL; @@ -265,10 +268,10 @@ public void visit(BLangPackage pkgNode) { find(pkgNode.typeDefinitions); find(pkgNode.classDefinitions.stream() .filter(c -> !isGeneratedClassDefForService(c)) - .collect(Collectors.toList())); + .toList()); find(pkgNode.functions.stream() .filter(f -> !f.flagSet.contains(Flag.LAMBDA)) - .collect(Collectors.toList())); + .toList()); if (!(pkgNode instanceof BLangTestablePackage)) { find(pkgNode.getTestablePkg()); @@ -632,7 +635,7 @@ public void visit(BLangFromClause fromClause) { @Override public void visit(BLangJoinClause joinClause) { find((BLangNode) joinClause.variableDefinitionNode); - find((BLangOnClause) joinClause.onClause); + find(joinClause.onClause); find(joinClause.collection); } @@ -813,7 +816,7 @@ public void visit(BLangRecordLiteral recordLiteral) { @Override public void visit(BLangTupleVarRef varRefExpr) { find(varRefExpr.expressions); - find((BLangNode) varRefExpr.restParam); + find(varRefExpr.restParam); } @Override @@ -822,7 +825,7 @@ public void visit(BLangRecordVarRef varRefExpr) { find(recordRefField.getBindingPattern()); } - find((BLangNode) varRefExpr.restParam); + find(varRefExpr.restParam); } @Override @@ -863,9 +866,9 @@ public void visit(BLangFieldBasedAccess fieldAccessExpr) { } @Override - public void visit(BLangNSPrefixedFieldBasedAccess nsPrefixedFieldBasedAccess) { - find(nsPrefixedFieldBasedAccess.expr); - addIfSameSymbol(nsPrefixedFieldBasedAccess.nsSymbol, nsPrefixedFieldBasedAccess.nsPrefix.pos); + public void visit(BLangPrefixedFieldBasedAccess prefixedFieldBasedAccess) { + find(prefixedFieldBasedAccess.expr); + addIfSameSymbol(prefixedFieldBasedAccess.symbol, prefixedFieldBasedAccess.prefix.pos); } @Override @@ -898,7 +901,7 @@ public void visit(BLangInvocation invocationExpr) { @Override public void visit(BLangTypeInit typeInit) { find(typeInit.userDefinedType); - find(typeInit.argsExpr); + find(typeInit.initInvocation); } @Override @@ -1323,11 +1326,36 @@ public void visit(BLangXMLElementAccess xmlElementAccess) { @Override public void visit(BLangXMLNavigationAccess xmlNavigation) { - find(xmlNavigation.childIndex); find(xmlNavigation.filters); find(xmlNavigation.expr); } + @Override + public void visit(BLangExtendedXMLNavigationAccess extendedXmlNavigationAccess) { + find(extendedXmlNavigationAccess.extensions); + find(extendedXmlNavigationAccess.stepExpr); + } + + @Override + public void visit(BLangXMLIndexedStepExtend xmlIndexedStepExtend) { + find(xmlIndexedStepExtend.indexExpr); + } + + @Override + public void visit(BLangXMLFilterStepExtend xmlFilterStepExtend) { + find(xmlFilterStepExtend.filters); + } + + @Override + public void visit(BLangXMLMethodCallStepExtend xmlMethodCallStepExtend) { + BLangInvocation invocation = xmlMethodCallStepExtend.invocation; + List argExprs = invocation.argExprs; + for (int i = 1; i < argExprs.size(); i++) { + find(argExprs.get(i)); + } + addIfSameSymbol(invocation.symbol, invocation.name.pos); + } + @Override public void visit(BLangClassDefinition classDefinition) { find(classDefinition.annAttachments); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/SymbolFactory.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/SymbolFactory.java index 77558f0d0e4a..b91b0c6824c4 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/SymbolFactory.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/SymbolFactory.java @@ -151,7 +151,7 @@ public Symbol getBCompiledSymbol(BSymbol symbol, String name) { throw new IllegalArgumentException("Symbol is 'null'"); } - if (symbol instanceof BVarSymbol) { + if (symbol instanceof BVarSymbol varSymbol) { if (symbol.kind == SymbolKind.FUNCTION && !isFunctionPointer(symbol)) { if (Symbols.isFlagOn(symbol.flags, Flags.ATTACHED)) { if (Symbols.isFlagOn(symbol.flags, Flags.RESOURCE)) { @@ -161,32 +161,32 @@ public Symbol getBCompiledSymbol(BSymbol symbol, String name) { } return createFunctionSymbol((BInvokableSymbol) symbol, name); } - if (symbol instanceof BConstantSymbol) { - return createConstantSymbol((BConstantSymbol) symbol, name); + if (symbol instanceof BConstantSymbol constantSymbol) { + return createConstantSymbol(constantSymbol, name); } if (symbol.kind == SymbolKind.WORKER) { return createWorkerSymbol((BWorkerSymbol) symbol, name); } if (symbol.owner instanceof BRecordTypeSymbol) { - return createRecordFieldSymbol((BVarSymbol) symbol); + return createRecordFieldSymbol(varSymbol); } if (symbol.owner instanceof BClassSymbol) { - return createClassFieldSymbol((BVarSymbol) symbol); + return createClassFieldSymbol(varSymbol); } if (symbol.owner instanceof BObjectTypeSymbol) { - return createObjectFieldSymbol((BVarSymbol) symbol); + return createObjectFieldSymbol(varSymbol); } if (Symbols.isFlagOn(symbol.flags, Flags.REQUIRED_PARAM)) { - return createBallerinaParameter((BVarSymbol) symbol, ParameterKind.REQUIRED); + return createBallerinaParameter(varSymbol, ParameterKind.REQUIRED); } if (Symbols.isFlagOn(symbol.flags, Flags.DEFAULTABLE_PARAM)) { - return createBallerinaParameter((BVarSymbol) symbol, ParameterKind.DEFAULTABLE); + return createBallerinaParameter(varSymbol, ParameterKind.DEFAULTABLE); } if (Symbols.isFlagOn(symbol.flags, Flags.INCLUDED)) { - return createBallerinaParameter((BVarSymbol) symbol, ParameterKind.INCLUDED_RECORD); + return createBallerinaParameter(varSymbol, ParameterKind.INCLUDED_RECORD); } if (Symbols.isFlagOn(symbol.flags, Flags.REST_PARAM)) { - return createBallerinaParameter((BVarSymbol) symbol, ParameterKind.REST); + return createBallerinaParameter(varSymbol, ParameterKind.REST); } if (symbol.kind == SymbolKind.PATH_PARAMETER) { return createPathParamSymbol(name, symbol, PathSegment.Kind.PATH_PARAMETER); @@ -196,26 +196,26 @@ public Symbol getBCompiledSymbol(BSymbol symbol, String name) { } // If the symbol is a wildcard('_'), a variable symbol will not be created. - if (((BVarSymbol) symbol).isWildcard) { + if (varSymbol.isWildcard) { return null; } // return the variable symbol - return createVariableSymbol((BVarSymbol) symbol, name); + return createVariableSymbol(varSymbol, name); } if (symbol instanceof BTypeSymbol) { if (symbol.kind == SymbolKind.ANNOTATION) { return createAnnotationSymbol((BAnnotationSymbol) symbol); } - if (symbol instanceof BPackageSymbol) { - return createModuleSymbol((BPackageSymbol) symbol, name); + if (symbol instanceof BPackageSymbol packageSymbol) { + return createModuleSymbol(packageSymbol, name); } - if (symbol instanceof BClassSymbol) { - return createClassSymbol((BClassSymbol) symbol, name); + if (symbol instanceof BClassSymbol classSymbol) { + return createClassSymbol(classSymbol, name); } - if (symbol instanceof BEnumSymbol) { - return createEnumSymbol((BEnumSymbol) symbol, name); + if (symbol instanceof BEnumSymbol enumSymbol) { + return createEnumSymbol(enumSymbol, name); } // For a type reference type symbol (SymTag.TYPE_REF) @@ -635,17 +635,16 @@ private BallerinaConstantValue createConstantValue(BLangConstantValue constantVa return null; } - if (constantValue.value instanceof BLangConstantValue) { - return createConstantValue((BLangConstantValue) constantValue.value); + if (constantValue.value instanceof BLangConstantValue bLangConstantValue) { + return createConstantValue(bLangConstantValue); } - if (constantValue.value instanceof HashMap) { - Map constValueMap = (Map) constantValue.value; + if (constantValue.value instanceof HashMap constValueMap) { Map constSymbolMap = new LinkedHashMap<>(); constValueMap.forEach((key, value) -> { BallerinaConstantValue newConstValue; - if (value instanceof BLangConstantValue) { - newConstValue = createConstantValue((BLangConstantValue) value); + if (value instanceof BLangConstantValue bLangConstantValue) { + newConstValue = createConstantValue(bLangConstantValue); constSymbolMap.put((String) key, newConstValue); } }); @@ -766,8 +765,8 @@ private String getMethodName(BInvokableSymbol method, BObjectTypeSymbol owner) { for (BAttachedFunction mthd : methods) { if (method == mthd.symbol) { - if (mthd instanceof BResourceFunction) { - return ((BResourceFunction) mthd).accessor.value; + if (mthd instanceof BResourceFunction bResourceFunction) { + return bResourceFunction.accessor.value; } return mthd.symbol.getOriginalName().getValue(); } @@ -803,8 +802,13 @@ private BAnnotationSymbol findAnnotationSymbol(BAnnotationAttachmentSymbol annot symTable.pkgEnvMap.get(symTable.langAnnotationModuleSymbol), annotTagRef); } + boolean testable = annotPkgId.isTestPkg; for (Entry entry : symTable.pkgEnvMap.entrySet()) { - if (entry.getKey().pkgID.equals(annotPkgId)) { + BPackageSymbol pkgSymbol = entry.getKey(); + if (pkgSymbol.pkgID.equals(annotPkgId)) { + if (testable && !pkgSymbol.pkgID.isTestPkg) { + continue; + } return (BAnnotationSymbol) symResolver.lookupSymbolInAnnotationSpace(entry.getValue(), annotTagRef); } } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/SymbolFinder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/SymbolFinder.java index 9b9ce5a2741a..948f17dc73d5 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/SymbolFinder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/SymbolFinder.java @@ -98,6 +98,7 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorConstructorExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangErrorVarRef; import org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangExtendedXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangFieldBasedAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangGroupExpr; import org.wso2.ballerinalang.compiler.tree.expressions.BLangIgnoreExpr; @@ -162,6 +163,9 @@ import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementFilter; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLElementLiteral; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLFilterStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLIndexedStepExtend; +import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLMethodCallStepExtend; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLNavigationAccess; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLProcInsLiteral; import org.wso2.ballerinalang.compiler.tree.expressions.BLangXMLQName; @@ -920,12 +924,12 @@ public void visit(BLangFieldBasedAccess fieldAccessExpr) { } @Override - public void visit(BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess nsPrefixedFieldBasedAccess) { - if (setEnclosingNode(nsPrefixedFieldBasedAccess.nsSymbol, nsPrefixedFieldBasedAccess.nsPrefix.pos)) { + public void visit(BLangFieldBasedAccess.BLangPrefixedFieldBasedAccess prefixedFieldBasedAccess) { + if (setEnclosingNode(prefixedFieldBasedAccess.symbol, prefixedFieldBasedAccess.prefix.pos)) { return; } - lookupNode(nsPrefixedFieldBasedAccess.expr); + lookupNode(prefixedFieldBasedAccess.expr); } @Override @@ -1670,10 +1674,30 @@ public void visit(BLangXMLElementAccess xmlElementAccess) { @Override public void visit(BLangXMLNavigationAccess xmlNavigation) { lookupNode(xmlNavigation.expr); - lookupNode(xmlNavigation.childIndex); lookupNodes(xmlNavigation.filters); } + @Override + public void visit(BLangExtendedXMLNavigationAccess extendedXmlNavigationAccess) { + lookupNode(extendedXmlNavigationAccess.stepExpr); + lookupNodes(extendedXmlNavigationAccess.extensions); + } + + @Override + public void visit(BLangXMLIndexedStepExtend xmlIndexedStepExtend) { + lookupNode(xmlIndexedStepExtend.indexExpr); + } + + @Override + public void visit(BLangXMLFilterStepExtend xmlFilterStepExtend) { + lookupNodes(xmlFilterStepExtend.filters); + } + + @Override + public void visit(BLangXMLMethodCallStepExtend xmlMethodCallStepExtend) { + lookupNode(xmlMethodCallStepExtend.invocation); + } + @Override public void visit(BLangInvocation.BLangResourceAccessInvocation resourceAccessInvocation) { lookupNodes(resourceAccessInvocation.annAttachments); @@ -1684,13 +1708,13 @@ public void visit(BLangInvocation.BLangResourceAccessInvocation resourceAccessIn // The assumption is that if it's moduled-qualified, it must be a public symbol. // Hence, the owner would be a package symbol. - if (resourceAccessInvocation.symbol != null && - setEnclosingNode(resourceAccessInvocation.symbol.owner, resourceAccessInvocation.pkgAlias.pos)) { + BSymbol symbol = resourceAccessInvocation.symbol; + if (symbol != null && setEnclosingNode(symbol.owner, resourceAccessInvocation.pkgAlias.pos)) { return; } if (this.symbolAtCursor == null) { - setEnclosingNode(resourceAccessInvocation.symbol, resourceAccessInvocation.resourceAccessPathSegments.pos); + setEnclosingNode(symbol, resourceAccessInvocation.name.pos); } } @@ -1781,7 +1805,7 @@ private void lookupResourceAccessPathSegments(BLangInvocation.BLangResourceAcces List pathSegSymbols = resourceInvocation.targetResourceFunc.pathSegmentSymbols; List pathExprs = resourceInvocation.resourceAccessPathSegments.exprs; - if (pathExprs.size() == 0 && pathSegSymbols.get(0).getKind() == SymbolKind.RESOURCE_ROOT_PATH_SEGMENT) { + if (pathExprs.isEmpty() && pathSegSymbols.get(0).getKind() == SymbolKind.RESOURCE_ROOT_PATH_SEGMENT) { // Returns since the resource-function has only the root-path segment // Assumption: If a resource-action with 0 path-expr matches with a resource function, // then it must have a root-path @@ -1830,10 +1854,9 @@ private boolean isLambdaFunction(TopLevelNode node) { } private boolean isWithinNodeMetaData(TopLevelNode node) { - if (node instanceof AnnotatableNode) { + if (node instanceof AnnotatableNode annotatableNode) { - List nodes = - (List) ((AnnotatableNode) node).getAnnotationAttachments(); + List nodes = annotatableNode.getAnnotationAttachments(); for (AnnotationAttachmentNode annotAttachment : nodes) { if (PositionUtil.withinBlock(this.cursorPos, annotAttachment.getPosition())) { @@ -1842,8 +1865,8 @@ private boolean isWithinNodeMetaData(TopLevelNode node) { } } - if (node instanceof DocumentableNode) { - BLangMarkdownDocumentation markdown = ((DocumentableNode) node).getMarkdownDocumentationAttachment(); + if (node instanceof DocumentableNode documentableNode) { + BLangMarkdownDocumentation markdown = documentableNode.getMarkdownDocumentationAttachment(); if (markdown != null) { LinkedList parameters = markdown.getParameters(); for (BLangMarkdownParameterDocumentation parameter : parameters) { diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/SyntaxNodeToLocationMapper.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/SyntaxNodeToLocationMapper.java index eb7e47e7fe28..62ec2b7efb01 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/SyntaxNodeToLocationMapper.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/SyntaxNodeToLocationMapper.java @@ -187,7 +187,10 @@ public Optional transform(RestParameterNode restParameterNode) { @Override public Optional transform(ClientResourceAccessActionNode clientResourceAccessActionNode) { - return Optional.of(clientResourceAccessActionNode.slashToken().location()); + if (clientResourceAccessActionNode.methodName().isEmpty()) { + return Optional.of(clientResourceAccessActionNode.slashToken().location()); + } + return Optional.of(clientResourceAccessActionNode.methodName().get().location()); } @Override diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/AbstractStructuredTypeSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/AbstractStructuredTypeSymbol.java new file mode 100644 index 000000000000..32d51fe58121 --- /dev/null +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/AbstractStructuredTypeSymbol.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (https://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.compiler.api.impl.symbols; + +import io.ballerina.compiler.api.symbols.TypeDescKind; +import io.ballerina.tools.diagnostics.Location; +import org.wso2.ballerinalang.compiler.semantics.model.types.BType; +import org.wso2.ballerinalang.compiler.util.CompilerContext; + +import java.util.Optional; + +/** + * Represents a Ballerina structured type descriptor. + * + * @since 2201.10.0 + */ +public abstract class AbstractStructuredTypeSymbol extends AbstractTypeSymbol { + + public AbstractStructuredTypeSymbol(CompilerContext context, + TypeDescKind typeDescKind, + BType bType) { + super(context, typeDescKind, bType); + } + + @Override + public Optional getLocation() { + return Optional.of(this.getBType().tsymbol.pos); + } +} diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaAnnotationSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaAnnotationSymbol.java index 59a5af8e5540..353bef7e61c2 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaAnnotationSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaAnnotationSymbol.java @@ -137,14 +137,15 @@ public static class AnnotationSymbolBuilder extends SymbolBuilder qualifiers = new ArrayList<>(); private TypeSymbol typeDescriptor; private List attachPoints; - private List annots = new ArrayList<>(); - private List annotAttachments = new ArrayList<>(); + private final List annots = new ArrayList<>(); + private final List annotAttachments = new ArrayList<>(); public AnnotationSymbolBuilder(String name, BAnnotationSymbol annotationSymbol, CompilerContext context) { super(name, SymbolKind.ANNOTATION, annotationSymbol, context); withAttachPoints(annotationSymbol); } + @Override public BallerinaAnnotationSymbol build() { return new BallerinaAnnotationSymbol(this.name, this.qualifiers, this.typeDescriptor, this.attachPoints, this.annots, this.annotAttachments, this.bSymbol, this.context); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaArrayTypeSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaArrayTypeSymbol.java index 3e9a4f7c4648..17be2846b014 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaArrayTypeSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaArrayTypeSymbol.java @@ -35,7 +35,7 @@ * * @since 2.0.0 */ -public class BallerinaArrayTypeSymbol extends AbstractTypeSymbol implements ArrayTypeSymbol { +public class BallerinaArrayTypeSymbol extends AbstractStructuredTypeSymbol implements ArrayTypeSymbol { private Integer size; private TypeSymbol memberTypeDesc; private String signature; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaConstantSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaConstantSymbol.java index 5b42cd3c3f74..4ce757e082fc 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaConstantSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaConstantSymbol.java @@ -33,7 +33,6 @@ import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.StringJoiner; @@ -49,7 +48,7 @@ public class BallerinaConstantSymbol extends BallerinaVariableSymbol implements ConstantSymbol { private final BallerinaConstantValue constValue; - private TypeSymbol broaderType; + private final TypeSymbol broaderType; private BallerinaConstantSymbol(String name, List qualifiers, List annots, List annotAttachments, TypeSymbol typeDescriptor, @@ -125,20 +124,19 @@ private String stringValueOf(BallerinaConstantValue value) { return null; } - if (value.value() instanceof BallerinaConstantValue) { - return stringValueOf((BallerinaConstantValue) value.value()); + if (value.value() instanceof BallerinaConstantValue ballerinaConstantValue) { + return stringValueOf(ballerinaConstantValue); } - if (value.value() instanceof HashMap) { + if (value.value() instanceof HashMap map) { StringJoiner joiner = new StringJoiner(", ", "{", "}"); - Map map = (Map) value.value(); map.forEach((k, v) -> { StringBuilder builder = new StringBuilder(); builder.append(k).append(": "); - if (v instanceof BallerinaConstantValue) { - builder.append(stringValueOf((BallerinaConstantValue) v)); + if (v instanceof BallerinaConstantValue ballerinaConstantValue) { + builder.append(stringValueOf(ballerinaConstantValue)); } else { builder.append(toStringVal(v, value.valueType())); } @@ -177,6 +175,7 @@ public ConstantSymbolBuilder(String name, BSymbol symbol, CompilerContext contex super(name, symbol, context); } + @Override public BallerinaConstantSymbol build() { return new BallerinaConstantSymbol(this.name, this.qualifiers, this.annots, this.annotAttachments, this.typeDescriptor, this.broaderType, this.constantValue, this.bSymbol, diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaDocumentation.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaDocumentation.java index 3a815fc0d87a..c1f0b6c91b99 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaDocumentation.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaDocumentation.java @@ -32,7 +32,7 @@ */ public class BallerinaDocumentation implements Documentation { - private MarkdownDocAttachment markdownDocAttachment; + private final MarkdownDocAttachment markdownDocAttachment; public BallerinaDocumentation(MarkdownDocAttachment markdownDocAttachment) { this.markdownDocAttachment = markdownDocAttachment; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaEnumSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaEnumSymbol.java index 0e02faea8e7f..32977e0eb880 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaEnumSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaEnumSymbol.java @@ -41,8 +41,8 @@ */ public class BallerinaEnumSymbol extends BallerinaTypeDefinitionSymbol implements EnumSymbol { - private List members; - private List annots; + private final List members; + private final List annots; private final List annotAttachments; protected BallerinaEnumSymbol(String name, List members, List qualifiers, diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaMapTypeSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaMapTypeSymbol.java index ee961d536481..412b6f309096 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaMapTypeSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaMapTypeSymbol.java @@ -31,7 +31,7 @@ * * @since 2.0.0 */ -public class BallerinaMapTypeSymbol extends AbstractTypeSymbol implements MapTypeSymbol { +public class BallerinaMapTypeSymbol extends AbstractStructuredTypeSymbol implements MapTypeSymbol { private TypeSymbol memberTypeDesc; private String signature; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaMemberTypeSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaMemberTypeSymbol.java index e86a6ef8a623..1334bcefa46c 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaMemberTypeSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaMemberTypeSymbol.java @@ -54,6 +54,7 @@ public Optional getName() { return Optional.empty(); } + @Override public TypeSymbol typeDescriptor() { return this.type; } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaModule.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaModule.java index f562e291dd70..7ac25ae7f3f5 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaModule.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaModule.java @@ -46,7 +46,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; import static org.ballerinalang.model.symbols.SymbolOrigin.BUILTIN; import static org.ballerinalang.model.symbols.SymbolOrigin.COMPILED_SOURCE; @@ -60,7 +59,7 @@ */ public class BallerinaModule extends BallerinaSymbol implements ModuleSymbol { - private BPackageSymbol packageSymbol; + private final BPackageSymbol packageSymbol; private List typeDefs; private List classes; private List functions; @@ -136,7 +135,7 @@ public List typeDefinitions() { this.typeDefs = this.allSymbols().stream() .filter(symbol -> symbol.kind() == SymbolKind.TYPE_DEFINITION) .map(symbol -> (TypeDefinitionSymbol) symbol) - .collect(Collectors.toUnmodifiableList()); + .toList(); } return this.typeDefs; @@ -263,11 +262,10 @@ public boolean equals(Object obj) { return true; } - if (!(obj instanceof ModuleSymbol)) { + if (!(obj instanceof ModuleSymbol symbol)) { return false; } - ModuleSymbol symbol = (ModuleSymbol) obj; return this.id().equals(symbol.id()); } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaObjectFieldSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaObjectFieldSymbol.java index 14ae5d9f7c04..efb5896cb83a 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaObjectFieldSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaObjectFieldSymbol.java @@ -55,7 +55,7 @@ public class BallerinaObjectFieldSymbol extends BallerinaSymbol implements Objec private TypeSymbol typeDescriptor; private List annots; private String signature; - private boolean deprecated; + private final boolean deprecated; private List annotAttachments; public BallerinaObjectFieldSymbol(CompilerContext context, BField bField, SymbolKind kind) { diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaObjectTypeSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaObjectTypeSymbol.java index fb637b99512e..c7eb00b3a536 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaObjectTypeSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaObjectTypeSymbol.java @@ -111,8 +111,7 @@ public Map methods() { Map methods = new LinkedHashMap<>(); for (BAttachedFunction attachedFunc : ((BObjectTypeSymbol) this.getBType().tsymbol).attachedFuncs) { - if (attachedFunc instanceof BResourceFunction) { - BResourceFunction resFn = (BResourceFunction) attachedFunc; + if (attachedFunc instanceof BResourceFunction resFn) { String resPath = resFn.pathSegmentSymbols.stream() .map(p -> p.name.value).collect(Collectors.joining("/")); methods.put(resFn.accessor.value + " " + resPath, diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaRecordFieldSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaRecordFieldSymbol.java index e5962a1116c0..4650cea13be3 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaRecordFieldSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaRecordFieldSymbol.java @@ -55,7 +55,7 @@ public class BallerinaRecordFieldSymbol extends BallerinaSymbol implements Recor private List annotAttachments; private List qualifiers; private String signature; - private boolean deprecated; + private final boolean deprecated; public BallerinaRecordFieldSymbol(CompilerContext context, BField bField) { super(bField.symbol.getOriginalName().value, SymbolKind.RECORD_FIELD, bField.symbol, context); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaRecordTypeSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaRecordTypeSymbol.java index d1f8d6c0935f..a288bb882344 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaRecordTypeSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaRecordTypeSymbol.java @@ -41,7 +41,7 @@ * * @since 2.0.0 */ -public class BallerinaRecordTypeSymbol extends AbstractTypeSymbol implements RecordTypeSymbol { +public class BallerinaRecordTypeSymbol extends AbstractStructuredTypeSymbol implements RecordTypeSymbol { private Map fieldSymbols; private TypeSymbol restTypeDesc; @@ -113,9 +113,7 @@ public String signature() { joiner.add(ballerinaFieldSignature); } - restTypeDescriptor().ifPresent(typeDescriptor -> { - joiner.add(typeDescriptor.signature() + "...;"); - }); + restTypeDescriptor().ifPresent(typeDescriptor -> joiner.add(typeDescriptor.signature() + "...;")); return "record " + joiner.toString(); } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaResourceMethodSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaResourceMethodSymbol.java index c1510e5b316d..370a20a6c2f4 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaResourceMethodSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaResourceMethodSymbol.java @@ -144,8 +144,8 @@ public T apply(SymbolTransformer transformer) { private BResourceFunction getBResourceFunction(List methods, BInvokableSymbol internalSymbol) { for (BAttachedFunction method : methods) { - if (internalSymbol == method.symbol && method instanceof BResourceFunction) { - return (BResourceFunction) method; + if (internalSymbol == method.symbol && method instanceof BResourceFunction bResourceFunction) { + return bResourceFunction; } } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaServiceDeclarationSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaServiceDeclarationSymbol.java index df2db95ac618..df06197ba142 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaServiceDeclarationSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaServiceDeclarationSymbol.java @@ -142,8 +142,7 @@ public Map fieldDescriptors() { Map methods = new LinkedHashMap<>(); for (BAttachedFunction method : classSymbol.attachedFuncs) { - if (method instanceof BResourceFunction) { - BResourceFunction resFn = (BResourceFunction) method; + if (method instanceof BResourceFunction resFn) { StringJoiner stringJoiner = new StringJoiner("/"); for (BResourcePathSegmentSymbol pathSegmentSym : resFn.pathSegmentSymbols) { diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaSymbol.java index 0bd8766412a5..2c30110360ff 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaSymbol.java @@ -149,11 +149,10 @@ public boolean equals(Object obj) { return true; } - if (!(obj instanceof Symbol)) { + if (!(obj instanceof Symbol symbol)) { return false; } - Symbol symbol = (Symbol) obj; return nameEquals(symbol.getName().orElse(null)) && isSameModule(this.getModule(), symbol.getModule()) && isSameLocation(this.getLocation(), symbol.getLocation()) diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaTableTypeSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaTableTypeSymbol.java index 31f8bd4ca9aa..0c8cbc75c5c0 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaTableTypeSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaTableTypeSymbol.java @@ -41,7 +41,7 @@ * * @since 2.0.0 */ -public class BallerinaTableTypeSymbol extends AbstractTypeSymbol implements TableTypeSymbol { +public class BallerinaTableTypeSymbol extends AbstractStructuredTypeSymbol implements TableTypeSymbol { private static final String ORG_NAME_BALLERINA = "ballerina"; private static final String MODULE_NAME_LANG_TABLE = "lang.table"; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaTupleTypeSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaTupleTypeSymbol.java index 18b7a2ea66b2..830334a8716e 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaTupleTypeSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaTupleTypeSymbol.java @@ -39,7 +39,7 @@ * * @since 2.0.0 */ -public class BallerinaTupleTypeSymbol extends AbstractTypeSymbol implements TupleTypeSymbol { +public class BallerinaTupleTypeSymbol extends AbstractStructuredTypeSymbol implements TupleTypeSymbol { private List memberTypes; private List tupleMembers; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaTypeReferenceTypeSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaTypeReferenceTypeSymbol.java index c01a04fbe96d..e68a1d5e22fd 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaTypeReferenceTypeSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaTypeReferenceTypeSymbol.java @@ -27,6 +27,7 @@ import io.ballerina.compiler.api.symbols.TypeReferenceTypeSymbol; import io.ballerina.compiler.api.symbols.TypeSymbol; import io.ballerina.tools.diagnostics.Location; +import org.ballerinalang.model.symbols.SymbolOrigin; import org.wso2.ballerinalang.compiler.semantics.model.Scope; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BSymbol; import org.wso2.ballerinalang.compiler.semantics.model.types.BParameterizedType; @@ -55,7 +56,7 @@ public class BallerinaTypeReferenceTypeSymbol extends AbstractTypeSymbol impleme private ModuleSymbol module; private Symbol definition; private boolean moduleEvaluated; - private boolean fromIntersectionType; + private final boolean fromIntersectionType; public BSymbol tSymbol; public BType referredType; @@ -103,7 +104,7 @@ public Symbol definition() { if (referredType.tag == TypeTags.PARAMETERIZED_TYPE || bType.tag == TypeTags.PARAMETERIZED_TYPE) { this.definition = symbolFactory.getBCompiledSymbol(((BParameterizedType) this.tSymbol.type).paramSymbol, this.name()); - } else if (referredType.tag == TypeTags.INTERSECTION) { + } else if (referredType.tag == TypeTags.INTERSECTION || referredType.tsymbol.origin == SymbolOrigin.VIRTUAL) { this.definition = symbolFactory.getBCompiledSymbol(bType.tsymbol, referredType.tsymbol.getName().getValue()); } else { diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaUnionTypeSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaUnionTypeSymbol.java index e6be4d916456..101f370bd464 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaUnionTypeSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaUnionTypeSymbol.java @@ -22,6 +22,7 @@ import io.ballerina.compiler.api.symbols.TypeDescKind; import io.ballerina.compiler.api.symbols.TypeSymbol; import io.ballerina.compiler.api.symbols.UnionTypeSymbol; +import io.ballerina.tools.diagnostics.Location; import org.ballerinalang.model.types.TypeKind; import org.wso2.ballerinalang.compiler.semantics.model.symbols.Symbols; import org.wso2.ballerinalang.compiler.semantics.model.types.BFiniteType; @@ -36,6 +37,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.StringJoiner; import java.util.regex.Pattern; @@ -231,4 +233,9 @@ private boolean containsTwoElements(List types) { } return false; } + + @Override + public Optional getLocation() { + return Optional.of(this.getBType().tsymbol.pos); + } } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaWorkerSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaWorkerSymbol.java index 213c181d8ff6..6930e8f6ccb8 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaWorkerSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/BallerinaWorkerSymbol.java @@ -37,8 +37,8 @@ */ public class BallerinaWorkerSymbol extends BallerinaSymbol implements WorkerSymbol { - private TypeSymbol returnType; - private List annots; + private final TypeSymbol returnType; + private final List annots; private final List annotAttachments; private BallerinaWorkerSymbol(String name, SymbolKind ballerinaSymbolKind, TypeSymbol returnType, diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/TypesFactory.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/TypesFactory.java index 892b9e6d355c..3c0705554eda 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/TypesFactory.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/TypesFactory.java @@ -173,8 +173,8 @@ private TypeSymbol createTypeDescriptor(BType bType, BTypeSymbol tSymbol) { case BYTE: return new BallerinaByteTypeSymbol(this.context, bType); case INT: - if (bType instanceof BIntSubType) { - return createIntSubType((BIntSubType) bType); + if (bType instanceof BIntSubType intSubType) { + return createIntSubType(intSubType); } return new BallerinaIntTypeSymbol(this.context, bType); case FLOAT: @@ -182,15 +182,15 @@ private TypeSymbol createTypeDescriptor(BType bType, BTypeSymbol tSymbol) { case DECIMAL: return new BallerinaDecimalTypeSymbol(this.context, bType); case STRING: - if (bType instanceof BStringSubType) { - return new BallerinaStringCharTypeSymbol(this.context, (BStringSubType) bType); + if (bType instanceof BStringSubType stringSubType) { + return new BallerinaStringCharTypeSymbol(this.context, stringSubType); } return new BallerinaStringTypeSymbol(this.context, bType); case ANY: return new BallerinaAnyTypeSymbol(this.context, (BAnyType) bType); case ANYDATA: - if (bType instanceof BRegexpType) { - return new BallerinaRegexpTypeSymbol(this.context, (BRegexpType) bType); + if (bType instanceof BRegexpType regexpType) { + return new BallerinaRegexpTypeSymbol(this.context, regexpType); } return new BallerinaAnydataTypeSymbol(this.context, (BAnydataType) bType); case HANDLE: @@ -202,8 +202,8 @@ private TypeSymbol createTypeDescriptor(BType bType, BTypeSymbol tSymbol) { case TABLE: return new BallerinaTableTypeSymbol(this.context, (BTableType) bType); case XML: - if (bType instanceof BXMLSubType) { - return createXMLSubType((BXMLSubType) bType); + if (bType instanceof BXMLSubType subType) { + return createXMLSubType(subType); } return new BallerinaXMLTypeSymbol(this.context, (BXMLType) bType); case OBJECT: @@ -265,37 +265,25 @@ private TypeSymbol createTypeDescriptor(BType bType, BTypeSymbol tSymbol) { } private IntTypeSymbol createIntSubType(BIntSubType internalType) { - switch (internalType.tag) { - case UNSIGNED8_INT: - return new BallerinaIntUnsigned8TypeSymbol(this.context, internalType); - case SIGNED8_INT: - return new BallerinaIntSigned8TypeSymbol(this.context, internalType); - case UNSIGNED16_INT: - return new BallerinaIntUnsigned16TypeSymbol(this.context, internalType); - case SIGNED16_INT: - return new BallerinaIntSigned16TypeSymbol(this.context, internalType); - case UNSIGNED32_INT: - return new BallerinaIntUnsigned32TypeSymbol(this.context, internalType); - case SIGNED32_INT: - return new BallerinaIntSigned32TypeSymbol(this.context, internalType); - } - - throw new IllegalStateException("Invalid integer subtype type tag: " + internalType.tag); + return switch (internalType.tag) { + case UNSIGNED8_INT -> new BallerinaIntUnsigned8TypeSymbol(this.context, internalType); + case SIGNED8_INT -> new BallerinaIntSigned8TypeSymbol(this.context, internalType); + case UNSIGNED16_INT -> new BallerinaIntUnsigned16TypeSymbol(this.context, internalType); + case SIGNED16_INT -> new BallerinaIntSigned16TypeSymbol(this.context, internalType); + case UNSIGNED32_INT -> new BallerinaIntUnsigned32TypeSymbol(this.context, internalType); + case SIGNED32_INT -> new BallerinaIntSigned32TypeSymbol(this.context, internalType); + default -> throw new IllegalStateException("Invalid integer subtype type tag: " + internalType.tag); + }; } private XMLTypeSymbol createXMLSubType(BXMLSubType internalType) { - switch (internalType.tag) { - case XML_ELEMENT: - return new BallerinaXMLElementTypeSymbol(this.context, internalType); - case XML_PI: - return new BallerinaXMLProcessingInstructionTypeSymbol(this.context, internalType); - case XML_COMMENT: - return new BallerinaXMLCommentTypeSymbol(this.context, internalType); - case XML_TEXT: - return new BallerinaXMLTextTypeSymbol(this.context, internalType); - } - - throw new IllegalStateException("Invalid XML subtype type tag: " + internalType.tag); + return switch (internalType.tag) { + case XML_ELEMENT -> new BallerinaXMLElementTypeSymbol(this.context, internalType); + case XML_PI -> new BallerinaXMLProcessingInstructionTypeSymbol(this.context, internalType); + case XML_COMMENT -> new BallerinaXMLCommentTypeSymbol(this.context, internalType); + case XML_TEXT -> new BallerinaXMLTextTypeSymbol(this.context, internalType); + default -> throw new IllegalStateException("Invalid XML subtype type tag: " + internalType.tag); + }; } public boolean isTypeReference(BType bType, BSymbol tSymbol, boolean rawTypeOnly) { @@ -325,74 +313,34 @@ public boolean isTypeReference(BType bType, BSymbol tSymbol, boolean rawTypeOnly } public static TypeDescKind getTypeDescKind(TypeKind bTypeKind) { - switch (bTypeKind) { - case ANY: - return TypeDescKind.ANY; - case ANYDATA: - return TypeDescKind.ANYDATA; - case ARRAY: - return TypeDescKind.ARRAY; - case BOOLEAN: - return TypeDescKind.BOOLEAN; - case BYTE: - return TypeDescKind.BYTE; - case DECIMAL: - return TypeDescKind.DECIMAL; - case FLOAT: - return TypeDescKind.FLOAT; - case HANDLE: - return TypeDescKind.HANDLE; - case INT: - return TypeDescKind.INT; - case NEVER: - return TypeDescKind.NEVER; - case NIL: - return TypeDescKind.NIL; - case STRING: - return TypeDescKind.STRING; - case JSON: - return TypeDescKind.JSON; - case XML: - return TypeDescKind.XML; - case FUNCTION: - return TypeDescKind.FUNCTION; - case FUTURE: - return TypeDescKind.FUTURE; - case MAP: - return TypeDescKind.MAP; - case OBJECT: - return TypeDescKind.OBJECT; - case STREAM: - return TypeDescKind.STREAM; - case TUPLE: - return TypeDescKind.TUPLE; - case TYPEDESC: - return TypeDescKind.TYPEDESC; - case UNION: - return TypeDescKind.UNION; - case INTERSECTION: - return TypeDescKind.INTERSECTION; - case ERROR: - return TypeDescKind.ERROR; - case NONE: - case OTHER: - return TypeDescKind.NONE; - case PARAMETERIZED: - case ANNOTATION: - case BLOB: - case CHANNEL: - case CONNECTOR: - case ENDPOINT: - case FINITE: - case PACKAGE: - case READONLY: - case SERVICE: - case TABLE: - case TYPEPARAM: - case VOID: - default: - return null; - } + return switch (bTypeKind) { + case ANY -> TypeDescKind.ANY; + case ANYDATA -> TypeDescKind.ANYDATA; + case ARRAY -> TypeDescKind.ARRAY; + case BOOLEAN -> TypeDescKind.BOOLEAN; + case BYTE -> TypeDescKind.BYTE; + case DECIMAL -> TypeDescKind.DECIMAL; + case FLOAT -> TypeDescKind.FLOAT; + case HANDLE -> TypeDescKind.HANDLE; + case INT -> TypeDescKind.INT; + case NEVER -> TypeDescKind.NEVER; + case NIL -> TypeDescKind.NIL; + case STRING -> TypeDescKind.STRING; + case JSON -> TypeDescKind.JSON; + case XML -> TypeDescKind.XML; + case FUNCTION -> TypeDescKind.FUNCTION; + case FUTURE -> TypeDescKind.FUTURE; + case MAP -> TypeDescKind.MAP; + case OBJECT -> TypeDescKind.OBJECT; + case STREAM -> TypeDescKind.STREAM; + case TUPLE -> TypeDescKind.TUPLE; + case TYPEDESC -> TypeDescKind.TYPEDESC; + case UNION -> TypeDescKind.UNION; + case INTERSECTION -> TypeDescKind.INTERSECTION; + case ERROR -> TypeDescKind.ERROR; + case NONE, OTHER -> TypeDescKind.NONE; + default -> null; + }; } private static boolean isCustomError(BSymbol tSymbol) { @@ -400,31 +348,29 @@ private static boolean isCustomError(BSymbol tSymbol) { } private static boolean isBuiltinNamedType(int tag) { - switch (tag) { - case INT: - case BYTE: - case FLOAT: - case DECIMAL: - case STRING: - case BOOLEAN: - case JSON: - case XML: - case NIL: - case ANY: - case ANYDATA: - case HANDLE: - case READONLY: - case NEVER: - case MAP: - case STREAM: - case TYPEDESC: - case TABLE: - case ERROR: - case FUTURE: - case SEMANTIC_ERROR: - return true; - } - - return false; + return switch (tag) { + case INT, + BYTE, + FLOAT, + DECIMAL, + STRING, + BOOLEAN, + JSON, + XML, + NIL, + ANY, + ANYDATA, + HANDLE, + READONLY, + NEVER, + MAP, + STREAM, + TYPEDESC, + TABLE, + ERROR, + FUTURE, + SEMANTIC_ERROR -> true; + default -> false; + }; } } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/resourcepath/BallerinaPathSegmentList.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/resourcepath/BallerinaPathSegmentList.java index ab6328eadcfa..f9c96bff3ad7 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/resourcepath/BallerinaPathSegmentList.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/symbols/resourcepath/BallerinaPathSegmentList.java @@ -32,7 +32,6 @@ import java.util.List; import java.util.Optional; import java.util.StringJoiner; -import java.util.stream.Collectors; /** * Represents an implementation of a path segment list. @@ -69,7 +68,7 @@ public List pathParameters() { List pathParams = new ArrayList<>(); int internalPathParamCount = 0; - List segments = this.internalPathSegmentSymbols.stream().map(s -> s.name).collect(Collectors.toList()); + List segments = this.internalPathSegmentSymbols.stream().map(s -> s.name).toList(); for (int i = 0; i < segments.size(); i++) { Name internalSegment = segments.get(i); BResourcePathSegmentSymbol pathSegSymbol = this.internalPathSegmentSymbols.get(i); @@ -139,19 +138,11 @@ public List list() { for (int i = 0, pathParamCount = 0, pathSegmentCount = this.internalPathSegmentSymbols.size(); i < pathSegmentCount; i++) { BResourcePathSegmentSymbol pathSegmentSymbol = this.internalPathSegmentSymbols.get(i); - PathSegment segment; - switch (pathSegmentSymbol.getName().getValue()) { - case "$^": - case "^": - segment = pathParams.get(pathParamCount++); - break; - case "^^": - case "$^^": - segment = pathRestParameter().get(); - break; - default: - segment = symbolFactory.createPathNameSymbol(pathSegmentSymbol); - } + PathSegment segment = switch (pathSegmentSymbol.getName().getValue()) { + case "$^", "^" -> pathParams.get(pathParamCount++); + case "^^", "$^^" -> pathRestParameter().get(); + default -> symbolFactory.createPathNameSymbol(pathSegmentSymbol); + }; segments.add(segment); } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaArrayTypeBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaArrayTypeBuilder.java index e39e679d200c..72702a3e9105 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaArrayTypeBuilder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaArrayTypeBuilder.java @@ -101,8 +101,8 @@ private BType getBType(TypeSymbol type) { throw new IllegalArgumentException("Array member type descriptor can not be null"); } - if (type instanceof AbstractTypeSymbol) { - return ((AbstractTypeSymbol) type).getBType(); + if (type instanceof AbstractTypeSymbol abstractTypeSymbol) { + return abstractTypeSymbol.getBType(); } throw new IllegalArgumentException("Invalid array member type descriptor provided"); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaFunctionTypeBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaFunctionTypeBuilder.java index cc530e2c1b2b..178519d7121a 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaFunctionTypeBuilder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaFunctionTypeBuilder.java @@ -122,8 +122,7 @@ private BVarSymbol getRestParamSymbol(ParameterSymbol restParam, BType restType) } BSymbol internalSymbol = ((BallerinaSymbol) restParam).getInternalSymbol(); - if (internalSymbol instanceof BVarSymbol) { - BVarSymbol varSymbol = (BVarSymbol) internalSymbol; + if (internalSymbol instanceof BVarSymbol varSymbol) { varSymbol.type = restType; return varSymbol; } @@ -150,8 +149,8 @@ private List getParamSymbols(List parameterSymbols) List params = new ArrayList<>(); for (ParameterSymbol parameterSymbol : parameterSymbols) { BSymbol internalSymbol = ((BallerinaSymbol) parameterSymbol).getInternalSymbol(); - if (internalSymbol instanceof BVarSymbol) { - params.add((BVarSymbol) internalSymbol); + if (internalSymbol instanceof BVarSymbol bVarSymbol) { + params.add(bVarSymbol); } } @@ -168,8 +167,8 @@ private List getParamTypes(List parameterSymbols) { } private BType getBType(TypeSymbol typeSymbol) { - if (typeSymbol instanceof AbstractTypeSymbol) { - return ((AbstractTypeSymbol) typeSymbol).getBType(); + if (typeSymbol instanceof AbstractTypeSymbol abstractTypeSymbol) { + return abstractTypeSymbol.getBType(); } throw new IllegalArgumentException("Invalid type provided"); @@ -180,8 +179,8 @@ private BType getReturnBType(TypeSymbol returnTypeSymbol) { return symTable.nilType; } - if (returnTypeSymbol instanceof AbstractTypeSymbol) { - return ((AbstractTypeSymbol) returnTypeSymbol).getBType(); + if (returnTypeSymbol instanceof AbstractTypeSymbol abstractTypeSymbol) { + return abstractTypeSymbol.getBType(); } throw new IllegalArgumentException("Invalid return type provided"); @@ -255,8 +254,8 @@ public ParameterSymbol build() { } private BType getBType(TypeSymbol typeSymbol) { - if (typeSymbol instanceof AbstractTypeSymbol) { - return ((AbstractTypeSymbol) typeSymbol).getBType(); + if (typeSymbol instanceof AbstractTypeSymbol abstractTypeSymbol) { + return abstractTypeSymbol.getBType(); } throw new IllegalArgumentException("Invalid type provided"); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaFutureTypeBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaFutureTypeBuilder.java index 6cf35d04f6c2..073cf34788a8 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaFutureTypeBuilder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaFutureTypeBuilder.java @@ -76,8 +76,8 @@ private BType getBType(TypeSymbol typeSymbol) { return null; } - if (typeSymbol instanceof AbstractTypeSymbol) { - return ((AbstractTypeSymbol) typeSymbol).getBType(); + if (typeSymbol instanceof AbstractTypeSymbol abstractTypeSymbol) { + return abstractTypeSymbol.getBType(); } return symTable.noType; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaObjectTypeBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaObjectTypeBuilder.java index f1c67ebaba80..ed7387eab7c7 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaObjectTypeBuilder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaObjectTypeBuilder.java @@ -60,7 +60,7 @@ public class BallerinaObjectTypeBuilder implements TypeBuilder.OBJECT { private final TypesFactory typesFactory; private final SymbolTable symTable; - private List qualifiers = new ArrayList<>(); + private final List qualifiers = new ArrayList<>(); private final List objectFieldList = new ArrayList<>(); private final List objectMethodList = new ArrayList<>(); private final List typeInclusions = new ArrayList<>(); @@ -176,10 +176,10 @@ symbolName, symbolName, symTable.rootPkgSymbol.pkgID, getBInvokableType(objectMe } private BInvokableType getBInvokableType(FunctionTypeSymbol type) { - if (type instanceof AbstractTypeSymbol) { - BType bType = ((AbstractTypeSymbol) type).getBType(); - if (bType instanceof BInvokableType) { - return (BInvokableType) bType; + if (type instanceof AbstractTypeSymbol abstractTypeSymbol) { + BType bType = abstractTypeSymbol.getBType(); + if (bType instanceof BInvokableType bInvokableType) { + return bInvokableType; } } @@ -212,8 +212,8 @@ ownerObjectTypeSymbol.pkgID, getBType(objectField.getType()), ownerObjectTypeSym private BType getBType(TypeSymbol typeSymbol) { if (typeSymbol != null) { - if (typeSymbol instanceof AbstractTypeSymbol) { - return ((AbstractTypeSymbol) typeSymbol).getBType(); + if (typeSymbol instanceof AbstractTypeSymbol abstractTypeSymbol) { + return abstractTypeSymbol.getBType(); } } @@ -222,8 +222,8 @@ private BType getBType(TypeSymbol typeSymbol) { private BType getTypeInclusionBType(TypeSymbol typeSymbol) { if (typeSymbol != null) { - if (typeSymbol instanceof AbstractTypeSymbol) { - return ((AbstractTypeSymbol) typeSymbol).getBType(); + if (typeSymbol instanceof AbstractTypeSymbol abstractTypeSymbol) { + return abstractTypeSymbol.getBType(); } throw new IllegalArgumentException("Invalid type provided"); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaRecordTypeBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaRecordTypeBuilder.java index e3541c1f3de3..33c88117390f 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaRecordTypeBuilder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaRecordTypeBuilder.java @@ -245,8 +245,8 @@ private List getTypeInclusions(List typeInclusio private BType getBType(TypeSymbol typeSymbol) { if (typeSymbol != null) { - if (typeSymbol instanceof AbstractTypeSymbol) { - return ((AbstractTypeSymbol) typeSymbol).getBType(); + if (typeSymbol instanceof AbstractTypeSymbol abstractTypeSymbol) { + return abstractTypeSymbol.getBType(); } throw new IllegalArgumentException("Invalid type provided"); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaSingletonTypeBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaSingletonTypeBuilder.java index 5fe02a612b22..148ebbed813b 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaSingletonTypeBuilder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaSingletonTypeBuilder.java @@ -89,23 +89,16 @@ public SingletonTypeSymbol build() { } private boolean isValidValueType(Object value, TypeSymbol typeSymbol) { - switch (typeSymbol.typeKind()) { - case STRING: - return value instanceof String || value instanceof Character; - case INT: - return value instanceof Integer; - case DECIMAL: - case FLOAT: - return value instanceof Float || value instanceof Double; - case BYTE: - return value instanceof Byte; - case BOOLEAN: - return value instanceof Boolean; - case NIL: - return value.equals("()"); - } + return switch (typeSymbol.typeKind()) { + case STRING -> value instanceof String || value instanceof Character; + case INT -> value instanceof Integer; + case DECIMAL, FLOAT -> value instanceof Float || value instanceof Double; + case BYTE -> value instanceof Byte; + case BOOLEAN -> value instanceof Boolean; + case NIL -> value.equals("()"); + default -> false; + }; - return false; } private BType getValueBType(TypeSymbol typeSymbol) { @@ -113,8 +106,8 @@ private BType getValueBType(TypeSymbol typeSymbol) { return symTable.noType; } - if (typeSymbol instanceof AbstractTypeSymbol) { - return ((AbstractTypeSymbol) typeSymbol).getBType(); + if (typeSymbol instanceof AbstractTypeSymbol abstractTypeSymbol) { + return abstractTypeSymbol.getBType(); } return symTable.anyType; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaStreamTypeBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaStreamTypeBuilder.java index c6ea682f5c5d..e71fc54136c9 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaStreamTypeBuilder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaStreamTypeBuilder.java @@ -86,16 +86,16 @@ private BType getValueBType(TypeSymbol valueType) { return symTable.anyType; } - if (valueType instanceof AbstractTypeSymbol) { - return ((AbstractTypeSymbol) valueType).getBType(); + if (valueType instanceof AbstractTypeSymbol abstractTypeSymbol) { + return abstractTypeSymbol.getBType(); } return symTable.noType; } private BType getCompletionBType(TypeSymbol completionType) { - if (completionType instanceof AbstractTypeSymbol) { - return ((AbstractTypeSymbol) completionType).getBType(); + if (completionType instanceof AbstractTypeSymbol abstractTypeSymbol) { + return abstractTypeSymbol.getBType(); } return symTable.nilType; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaTableTypeBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaTableTypeBuilder.java index da222627a608..18af7c102770 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaTableTypeBuilder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaTableTypeBuilder.java @@ -123,8 +123,8 @@ public TableTypeSymbol build() { private boolean isValidFieldNameList(List fieldNames, TypeSymbol rowType) { // check if a key field name exist in the rowType's record fields as a readonly field. - if (rowType instanceof RecordTypeSymbol) { - Map fieldDescriptors = ((RecordTypeSymbol) rowType).fieldDescriptors(); + if (rowType instanceof RecordTypeSymbol recordTypeSymbol) { + Map fieldDescriptors = recordTypeSymbol.fieldDescriptors(); for (String fieldName : fieldNames) { if (!fieldDescriptors.containsKey(fieldName)) { return false; @@ -144,8 +144,8 @@ private boolean isValidFieldNameList(List fieldNames, TypeSymbol rowType private boolean isReadOnlyField(RecordFieldSymbol recordField) { TypeSymbol typeDescriptor = recordField.typeDescriptor(); - if (typeDescriptor instanceof AbstractTypeSymbol) { - BType bType = ((AbstractTypeSymbol) typeDescriptor).getBType(); + if (typeDescriptor instanceof AbstractTypeSymbol abstractTypeSymbol) { + BType bType = abstractTypeSymbol.getBType(); return Symbols.isFlagOn(bType.flags, Flags.READONLY); } @@ -192,16 +192,16 @@ private BType checkKeyConstraintBType(TypeSymbol keyType, TypeSymbol rowType) { private boolean isValidKeyConstraintType(TypeSymbol fieldType, TypeSymbol keyType) { if ((fieldType.typeKind() == keyType.typeKind() || keyType.subtypeOf(fieldType)) - && fieldType instanceof AbstractTypeSymbol) { - return Symbols.isFlagOn(((AbstractTypeSymbol) fieldType).getBType().flags, Flags.READONLY); + && fieldType instanceof AbstractTypeSymbol abstractTypeSymbol) { + return Symbols.isFlagOn(abstractTypeSymbol.getBType().flags, Flags.READONLY); } return false; } private BType getKeyBType(TypeSymbol typeSymbol) { - if (typeSymbol instanceof AbstractTypeSymbol) { - return ((AbstractTypeSymbol) typeSymbol).getBType(); + if (typeSymbol instanceof AbstractTypeSymbol abstractTypeSymbol) { + return abstractTypeSymbol.getBType(); } throw new IllegalArgumentException("Invalid key type parameter provided"); @@ -214,12 +214,11 @@ private BType getRowBType(TypeSymbol rowType, boolean isKeyless) { BType rowBType = getBType(rowType); if (types.isAssignable(rowBType, symTable.mapType)) { - if (rowBType instanceof BRecordType) { - if (isKeyless || isValidRowRecordType((BRecordType) rowBType)) { + if (rowBType instanceof BRecordType bRecordType) { + if (isKeyless || isValidRowRecordType(bRecordType)) { return rowBType; } - } else if (rowBType instanceof BMapType) { - BMapType rowMapType = (BMapType) rowBType; + } else if (rowBType instanceof BMapType rowMapType) { BType mapTypeConstraint = rowMapType.getConstraint(); if (types.isAssignable(mapTypeConstraint, symTable.pureType)) { return rowBType; @@ -245,9 +244,9 @@ private boolean isValidRowRecordType(BRecordType rowBType) { private BType getBType(TypeSymbol typeSymbol) { if (typeSymbol != null) { - if (typeSymbol instanceof AbstractTypeSymbol + if (typeSymbol instanceof AbstractTypeSymbol abstractTypeSymbol && typeSymbol.subtypeOf(typesFactory.getTypeDescriptor(symTable.anyType))) { - return ((AbstractTypeSymbol) typeSymbol).getBType(); + return abstractTypeSymbol.getBType(); } throw new IllegalArgumentException("Invalid type parameter provided"); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaTupleTypeBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaTupleTypeBuilder.java index 144de73a9fa2..9b401688b982 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaTupleTypeBuilder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaTupleTypeBuilder.java @@ -100,13 +100,13 @@ private BType getMemberType(TypeSymbol memberType) { throw new IllegalArgumentException("Member type provided to the Tuple type descriptor can not be null."); } - if (memberType instanceof AbstractTypeSymbol) { - return ((AbstractTypeSymbol) memberType).getBType(); + if (memberType instanceof AbstractTypeSymbol abstractTypeSymbol) { + return abstractTypeSymbol.getBType(); } return symTable.noType; } private BType getRestType(TypeSymbol restType) { - return restType instanceof AbstractTypeSymbol ? ((AbstractTypeSymbol) restType).getBType() : null; + return restType instanceof AbstractTypeSymbol abstractTypeSymbol ? abstractTypeSymbol.getBType() : null; } } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaTypeDescTypeBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaTypeDescTypeBuilder.java index 5629708e8a74..d387090e8562 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaTypeDescTypeBuilder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaTypeDescTypeBuilder.java @@ -72,8 +72,8 @@ public TypeDescTypeSymbol build() { private BType getBType(TypeSymbol typeSymbol) { if (typeSymbol != null) { - if (typeSymbol instanceof AbstractTypeSymbol) { - return ((AbstractTypeSymbol) typeSymbol).getBType(); + if (typeSymbol instanceof AbstractTypeSymbol abstractTypeSymbol) { + return abstractTypeSymbol.getBType(); } return symTable.noType; } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaUnionTypeBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaUnionTypeBuilder.java index 106c589d7fdb..fd0d90aec70a 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaUnionTypeBuilder.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/type/builders/BallerinaUnionTypeBuilder.java @@ -85,22 +85,22 @@ public UnionTypeSymbol build() { } private BType[] getMemberBTypes() { - if (memberTypes.size() == 0) { + if (memberTypes.isEmpty()) { throw new IllegalArgumentException("Member types can not be empty"); } List bTypeList = new ArrayList<>(); for (TypeSymbol memberType : memberTypes) { - if (memberType instanceof AbstractTypeSymbol) { - bTypeList.add(((AbstractTypeSymbol) memberType).getBType()); + if (memberType instanceof AbstractTypeSymbol abstractTypeSymbol) { + bTypeList.add(abstractTypeSymbol.getBType()); continue; } if ((memberType instanceof ClassSymbol || memberType instanceof ConstantSymbol || memberType instanceof EnumSymbol) - && memberType instanceof BallerinaSymbol) { - bTypeList.add(((BallerinaSymbol) memberType).getInternalSymbol().getType()); + && memberType instanceof BallerinaSymbol ballerinaSymbol) { + bTypeList.add(ballerinaSymbol.getInternalSymbol().getType()); continue; } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/util/SymbolUtils.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/util/SymbolUtils.java index c48b6416cc0e..dcef4293e015 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/util/SymbolUtils.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/util/SymbolUtils.java @@ -44,7 +44,10 @@ /** * Common util methods related to symbols. */ -public class SymbolUtils { +public final class SymbolUtils { + + private SymbolUtils() { + } public static String unescapeUnicode(String value) { if (value.startsWith("'")) { @@ -57,34 +60,22 @@ public static Optional getTypeDescriptor(Symbol symbol) { if (symbol == null) { return Optional.empty(); } - switch (symbol.kind()) { - case TYPE_DEFINITION: - return Optional.ofNullable(((TypeDefinitionSymbol) symbol).typeDescriptor()); - case VARIABLE: - return Optional.ofNullable(((VariableSymbol) symbol).typeDescriptor()); - case PARAMETER: - return Optional.ofNullable(((ParameterSymbol) symbol).typeDescriptor()); - case ANNOTATION: - return ((AnnotationSymbol) symbol).typeDescriptor(); - case FUNCTION: - case METHOD: - return Optional.ofNullable(((FunctionSymbol) symbol).typeDescriptor()); - case CONSTANT: - case ENUM_MEMBER: - return Optional.ofNullable(((ConstantSymbol) symbol).typeDescriptor()); - case CLASS: - return Optional.of((ClassSymbol) symbol); - case RECORD_FIELD: - return Optional.ofNullable(((RecordFieldSymbol) symbol).typeDescriptor()); - case OBJECT_FIELD: - return Optional.of(((ObjectFieldSymbol) symbol).typeDescriptor()); - case CLASS_FIELD: - return Optional.of(((ClassFieldSymbol) symbol).typeDescriptor()); - case TYPE: - return Optional.of((TypeSymbol) symbol); - default: - return Optional.empty(); - } + return switch (symbol.kind()) { + case TYPE_DEFINITION -> Optional.ofNullable(((TypeDefinitionSymbol) symbol).typeDescriptor()); + case VARIABLE -> Optional.ofNullable(((VariableSymbol) symbol).typeDescriptor()); + case PARAMETER -> Optional.ofNullable(((ParameterSymbol) symbol).typeDescriptor()); + case ANNOTATION -> ((AnnotationSymbol) symbol).typeDescriptor(); + case FUNCTION, + METHOD -> Optional.ofNullable(((FunctionSymbol) symbol).typeDescriptor()); + case CONSTANT, + ENUM_MEMBER -> Optional.ofNullable(((ConstantSymbol) symbol).typeDescriptor()); + case CLASS -> Optional.of((ClassSymbol) symbol); + case RECORD_FIELD -> Optional.ofNullable(((RecordFieldSymbol) symbol).typeDescriptor()); + case OBJECT_FIELD -> Optional.of(((ObjectFieldSymbol) symbol).typeDescriptor()); + case CLASS_FIELD -> Optional.of(((ClassFieldSymbol) symbol).typeDescriptor()); + case TYPE -> Optional.of((TypeSymbol) symbol); + default -> Optional.empty(); + }; } /** @@ -94,24 +85,20 @@ public static Optional getTypeDescriptor(Symbol symbol) { * @return The bound type based on the kind of the input BType. Returns null if the kind is not supported. */ public static BType getTypeParamBoundType(BType type) { - switch (type.getKind()) { - case MAP: - return ((BMapType) type).constraint; - case ARRAY: - return ((BArrayType) type).eType; - case TABLE: - return ((BTableType) type).constraint; - case STREAM: - return ((BStreamType) type).constraint; - case XML: - if (type.tag == TypeTags.XML) { - return ((BXMLType) type).constraint; - } - return type; - // The following explicitly mentioned type kinds should be supported, but they are not for the moment. - case ERROR: - default: - return null; - } + return switch (type.getKind()) { + case MAP -> ((BMapType) type).constraint; + case ARRAY -> ((BArrayType) type).eType; + case TABLE -> ((BTableType) type).constraint; + case STREAM -> ((BStreamType) type).constraint; + case XML -> { + if (type.tag == TypeTags.XML) { + yield ((BXMLType) type).constraint; + } + yield type; + } + // The following explicitly mentioned type kinds should be supported, but they are not for the moment. + case ERROR -> null; + default -> null; + }; } } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/values/BallerinaConstantValue.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/values/BallerinaConstantValue.java index 4e25f7ab9f4b..68224d6872ae 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/values/BallerinaConstantValue.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/impl/values/BallerinaConstantValue.java @@ -36,10 +36,12 @@ public BallerinaConstantValue(Object value, TypeSymbol valueType) { this.valueType = valueType; } + @Override public Object value() { return value; } + @Override public TypeSymbol valueType() { return valueType; } @@ -59,8 +61,7 @@ public boolean equals(Object o) { return false; } - if (o instanceof BallerinaConstantValue) { - BallerinaConstantValue that = (BallerinaConstantValue) o; + if (o instanceof BallerinaConstantValue that) { if (this.valueType != that.valueType) { return false; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/symbols/AnnotationAttachPoint.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/symbols/AnnotationAttachPoint.java index 446ffc342902..104aa05e6342 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/symbols/AnnotationAttachPoint.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/symbols/AnnotationAttachPoint.java @@ -40,5 +40,5 @@ public enum AnnotationAttachPoint { EXTERNAL, VAR, CONST, - WORKER; + WORKER } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/symbols/ClassSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/symbols/ClassSymbol.java index d2f47add4392..3f956333f34a 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/symbols/ClassSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/symbols/ClassSymbol.java @@ -34,6 +34,7 @@ public interface ClassSymbol extends ObjectTypeSymbol, Qualifiable, Deprecatable * * @return An ordered map containing the symbols of the fields */ + @Override Map fieldDescriptors(); /** diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/symbols/ParameterSymbol.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/symbols/ParameterSymbol.java index 1af8cafa7b3a..ba087e056a2f 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/symbols/ParameterSymbol.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/symbols/ParameterSymbol.java @@ -30,6 +30,7 @@ public interface ParameterSymbol extends Symbol, Annotatable, Qualifiable { * * @return {@link Optional} name of the field */ + @Override Optional getName(); /** diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/symbols/TypeDescKind.java b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/symbols/TypeDescKind.java index ca5f066b3e1b..2ff3aa166685 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/symbols/TypeDescKind.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/compiler/api/symbols/TypeDescKind.java @@ -77,32 +77,26 @@ public String getName() { } public boolean isIntegerType() { - switch (this) { - case INT: - case INT_SIGNED8: - case INT_UNSIGNED8: - case INT_SIGNED16: - case INT_UNSIGNED16: - case INT_SIGNED32: - case INT_UNSIGNED32: - case BYTE: - return true; - } + return switch (this) { + case INT, + INT_SIGNED8, + INT_UNSIGNED8, + INT_SIGNED16, + INT_UNSIGNED16, + INT_SIGNED32, + INT_UNSIGNED32, + BYTE -> true; + default -> false; + }; - return false; } public boolean isXMLType() { - switch (this) { - case XML: - case XML_COMMENT: - case XML_ELEMENT: - case XML_PROCESSING_INSTRUCTION: - case XML_TEXT: - return true; - } + return switch (this) { + case XML, XML_COMMENT, XML_ELEMENT, XML_PROCESSING_INSTRUCTION, XML_TEXT -> true; + default -> false; + }; - return false; } public boolean isStringType() { diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/AnyTarget.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/AnyTarget.java index 49100620f1ab..aa5e9332ec5c 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/AnyTarget.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/AnyTarget.java @@ -33,6 +33,7 @@ public enum AnyTarget implements CompilerBackend.TargetPlatform { this.code = code; } + @Override public String code() { return code; } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalCommand.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalCommand.java new file mode 100644 index 000000000000..e2ae1f86dc70 --- /dev/null +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalCommand.java @@ -0,0 +1,21 @@ +// Copyright (c) 2024 WSO2 LLC. (http://www.wso2.com) All Rights Reserved. +// +// WSO2 Inc. 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.projects; + +public enum BalCommand { + BUILD, + TEST +} diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalToolToml.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalToolToml.java index f34bc8ee88ca..834ac86feb02 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalToolToml.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalToolToml.java @@ -27,8 +27,8 @@ * @since 2201.6.0 */ public class BalToolToml { - private TomlDocumentContext balToolTomlContext; - private Package packageInstance; + private final TomlDocumentContext balToolTomlContext; + private final Package packageInstance; private BalToolToml(TomlDocumentContext balToolTomlContext, Package packageInstance) { this.balToolTomlContext = balToolTomlContext; @@ -73,7 +73,7 @@ public BalToolToml.Modifier modify() { */ public static class Modifier { private TomlDocument tomlDocument; - private Package oldPackage; + private final Package oldPackage; private Modifier(BalToolToml oldDocument) { this.tomlDocument = oldDocument.tomlDocument(); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalToolsManifest.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalToolsManifest.java index 8164aece980f..8cf67d265bba 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalToolsManifest.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalToolsManifest.java @@ -108,7 +108,7 @@ public static class Tool { private final String name; private final String version; private Boolean active; - private String repository; + private final String repository; public Tool(String id, String org, String name, String version, Boolean active, String repository) { this.id = id; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalToolsToml.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalToolsToml.java index 10820cd1d1ac..99b7e4fec852 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalToolsToml.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalToolsToml.java @@ -135,10 +135,12 @@ private void write(String content) { } private String getAutoGenCode() { - return "# AUTO-GENERATED FILE. DO NOT MODIFY.\n" + - "\n" + - "# This file is auto-generated by Ballerina for managing tool commands.\n" + - "# It should not be modified by hand.\n" + - "\n"; + return """ + # AUTO-GENERATED FILE. DO NOT MODIFY. + + # This file is auto-generated by Ballerina for managing tool commands. + # It should not be modified by hand. + + """; } } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalaWriter.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalaWriter.java index f68c123d1b34..0d5e8ca23d67 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalaWriter.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BalaWriter.java @@ -49,13 +49,15 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipOutputStream; @@ -65,6 +67,7 @@ import static io.ballerina.projects.util.ProjectConstants.DEPENDENCY_GRAPH_JSON; import static io.ballerina.projects.util.ProjectConstants.PACKAGE_JSON; import static io.ballerina.projects.util.ProjectUtils.getBalaName; +import static io.ballerina.projects.util.ProjectUtils.getConflictingResourcesMsg; /** * {@code BalaWriter} writes a package to bala format. @@ -78,6 +81,7 @@ public abstract class BalaWriter { protected static final String PLATFORM = "platform"; protected static final String PATH = "path"; private static final String MAIN_BAL = "main.bal"; + private static final String UNIX_FILE_SEPARATOR = "/"; // Set the target as any for default bala. protected String target = "any"; @@ -128,6 +132,7 @@ private void populateBalaArchive(ZipOutputStream balaOutputStream) this.packageContext.project().sourceRoot(), this.packageContext.packageName().toString()); addPackageSource(balaOutputStream); + addResources(balaOutputStream); addIncludes(balaOutputStream); Optional platformLibs = addPlatformLibs(balaOutputStream); addPackageJson(balaOutputStream, platformLibs); @@ -141,7 +146,7 @@ private void addBalaJson(ZipOutputStream balaOutputStream) { Gson gson = new GsonBuilder().setPrettyPrinting().create(); String balaJson = gson.toJson(new BalaJson()); try { - putZipEntry(balaOutputStream, Paths.get(BALA_JSON), + putZipEntry(balaOutputStream, Path.of(BALA_JSON), new ByteArrayInputStream(balaJson.getBytes(Charset.defaultCharset()))); } catch (IOException e) { throw new ProjectException("Failed to write 'bala.json' file: " + e.getMessage(), e); @@ -168,14 +173,12 @@ private void addPackageJson(ZipOutputStream balaOutputStream, Optional platforms = packageManifest.platforms(); + Boolean allPlatformDepsGraalvmCompatible = isAllPlatformDepsGraalvmCompatible(packageManifest.platforms()); PackageManifest.Platform targetPlatform = packageManifest.platform(target); if (platforms != null) { if (targetPlatform != null) { Boolean graalvmCompatible = targetPlatform.graalvmCompatible(); if (graalvmCompatible != null) { - // If the package explicitly specifies the graalvmCompatibility property, then use it - packageJson.setGraalvmCompatible(graalvmCompatible); + // If the package explicitly specifies the graalvmCompatibility property, then use it unless + // no individual dependency is incompatible + boolean finalCompatibility = (allPlatformDepsGraalvmCompatible != null) ? + (allPlatformDepsGraalvmCompatible && graalvmCompatible) : graalvmCompatible; + packageJson.setGraalvmCompatible(finalCompatibility); return; } } - if (!otherPlatformGraalvmCompatibleVerified(target, packageManifest.platforms()).equals("")) { + if (!otherPlatformGraalvmCompatibleVerified(target, packageManifest.platforms()).isEmpty()) { Boolean otherGraalvmCompatible = packageManifest.platform(otherPlatformGraalvmCompatibleVerified(target, packageManifest.platforms())).graalvmCompatible(); - packageJson.setGraalvmCompatible(otherGraalvmCompatible); - } else if (!hasExternalPlatformDependencies(packageManifest.platforms())) { - // If the package uses only distribution provided platform libraries, then package is graalvm compatible - packageJson.setGraalvmCompatible(true); + boolean finalCompatibility = (allPlatformDepsGraalvmCompatible != null) ? + (allPlatformDepsGraalvmCompatible && otherGraalvmCompatible) : otherGraalvmCompatible; + packageJson.setGraalvmCompatible(finalCompatibility); + return; } + // If the package uses only distribution provided platform libraries, then package is graalvm compatible + // If platform libraries are specified with 'graalvmCompatible', infer the overall compatibility. + packageJson.setGraalvmCompatible(allPlatformDepsGraalvmCompatible); } else { // If the package uses only distribution provided platform libraries // or has only ballerina dependencies, then the package is graalvm compatible @@ -219,6 +229,18 @@ private void setGraalVMCompatibilityProperty(PackageJson packageJson, PackageMan } } + private static Boolean isAllPlatformDepsGraalvmCompatible(Map platforms) { + Boolean isAllDepsGraalvmCompatible = true; + for (PackageManifest.Platform platform: platforms.values()) { + if (platform.isPlatfromDepsGraalvmCompatible() == null) { + isAllDepsGraalvmCompatible = null; + } else if (!platform.isPlatfromDepsGraalvmCompatible()) { + return false; + } + } + return isAllDepsGraalvmCompatible; + } + private String otherPlatformGraalvmCompatibleVerified(String target, Map platforms) { for (Map.Entry platform : platforms.entrySet()) { @@ -229,16 +251,6 @@ private String otherPlatformGraalvmCompatibleVerified(String target, return ""; } - private boolean hasExternalPlatformDependencies(Map platforms) { - // Check if external platform dependencies are defined - for (PackageManifest.Platform platformVal: platforms.values()) { - if (!platformVal.dependencies().isEmpty()) { - return true; - } - } - return false; - } - // TODO when iterating and adding source files should create source files from Package sources private void addPackageDoc(ZipOutputStream balaOutputStream, Path packageSourceDir, String pkgName) @@ -247,7 +259,7 @@ private void addPackageDoc(ZipOutputStream balaOutputStream, Path packageSourceD final String moduleMdFileName = "Module.md"; Path packageMd = packageSourceDir.resolve(packageMdFileName); - Path docsDirInBala = Paths.get(BALA_DOCS_DIR); + Path docsDirInBala = Path.of(BALA_DOCS_DIR); // If `Package.md` exists, create the docs directory & add `Package.md` if (packageMd.toFile().exists()) { @@ -301,20 +313,14 @@ private void addPackageSource(ZipOutputStream balaOutputStream) throws IOExcepti for (ModuleId moduleId : this.packageContext.moduleIds()) { Module module = this.packageContext.project().currentPackage().module(moduleId); - // copy resources - for (DocumentId documentId : module.resourceIds()) { - Resource resource = module.resource(documentId); - Path resourcePath = Paths.get(ProjectConstants.MODULES_ROOT).resolve(module.moduleName().toString()) - .resolve(RESOURCE_DIR_NAME).resolve(resource.name()); - putZipEntry(balaOutputStream, resourcePath, new ByteArrayInputStream(resource.content())); - } - // Generate empty bal file for default module in tools - if (module.isDefaultModule() && !packageContext.balToolTomlContext().isEmpty() && + if (module.isDefaultModule() && packageContext.balToolTomlContext().isPresent() && module.documentIds().isEmpty()) { - String emptyBalContent = "// AUTO-GENERATED FILE.\n" + - "\n" + - "// This file is auto-generated by Ballerina for packages with empty default modules. \n"; + String emptyBalContent = """ + // AUTO-GENERATED FILE. + + // This file is auto-generated by Ballerina for packages with empty default modules.\s + """; TextDocument emptyBalTextDocument = TextDocuments.from(emptyBalContent); DocumentId documentId = DocumentId.create(MAIN_BAL, moduleId); @@ -327,7 +333,7 @@ private void addPackageSource(ZipOutputStream balaOutputStream) throws IOExcepti for (DocumentId docId : module.documentIds()) { Document document = module.document(docId); if (document.name().endsWith(BLANG_SOURCE_EXT)) { - Path documentPath = Paths.get(MODULES_ROOT, module.moduleName().toString(), document.name()); + Path documentPath = Path.of(MODULES_ROOT, module.moduleName().toString(), document.name()); char[] documentContent = document.textDocument().toCharArray(); putZipEntry(balaOutputStream, documentPath, @@ -337,6 +343,38 @@ private void addPackageSource(ZipOutputStream balaOutputStream) throws IOExcepti } } + private void addResources(ZipOutputStream balaOutputStream) throws IOException { + Set resourceFiles = new HashSet<>(); + + // copy resources + for (DocumentId documentId : packageContext.resourceIds()) { + String resourceFile = packageContext.resourceContext(documentId).name(); + Path resourcePath = Path.of(RESOURCE_DIR_NAME).resolve(resourceFile); + if (resourceFiles.add(resourcePath.toString())) { + putZipEntry(balaOutputStream, resourcePath, new ByteArrayInputStream( + packageContext.resourceContext(documentId).content())); + } + } + + // copy resources from `target/resources` + if (packageContext.project().kind().equals(ProjectKind.BUILD_PROJECT)) { + Map cachedResources = ProjectUtils.getAllGeneratedResources( + packageContext.project().generatedResourcesDir()); + List conflictingResourceFiles = cachedResources.keySet().stream() + .filter(path -> !resourceFiles.add(path)) + .collect(Collectors.toList()); + + if (!conflictingResourceFiles.isEmpty()) { + throw new ProjectException(getConflictingResourcesMsg( + packageContext.descriptor().toString(), conflictingResourceFiles)); + } + + for (Map.Entry entry : cachedResources.entrySet()) { + putZipEntry(balaOutputStream, Path.of(entry.getKey()), new ByteArrayInputStream(entry.getValue())); + } + } + } + private void addIncludes(ZipOutputStream balaOutputStream) throws IOException { List includePatterns = this.packageContext.packageManifest().includes(); List includePaths = ProjectUtils.getPathsMatchingIncludePatterns( @@ -373,7 +411,7 @@ private void addDependenciesJson(ZipOutputStream balaOutputStream) { Gson gson = new GsonBuilder().setPrettyPrinting().create(); try { - putZipEntry(balaOutputStream, Paths.get(DEPENDENCY_GRAPH_JSON), + putZipEntry(balaOutputStream, Path.of(DEPENDENCY_GRAPH_JSON), new ByteArrayInputStream(gson.toJson(depGraphJson).getBytes(Charset.defaultCharset()))); } catch (IOException e) { throw new ProjectException("Failed to write '" + DEPENDENCY_GRAPH_JSON + "' file: " + e.getMessage(), e); @@ -388,7 +426,7 @@ private Path updateModuleDirectoryToMatchNamingInBala(Path relativePath) { String packageName = this.packageContext.packageName().toString(); Path modulePath = moduleRootPath.resolve(moduleRootPath.relativize(relativePath).subpath(0, 1)); Path pathInsideModule = modulePath.relativize(relativePath); - String moduleName = Optional.ofNullable(modulePath.getFileName()).orElse(Paths.get("")).toString(); + String moduleName = Optional.ofNullable(modulePath.getFileName()).orElse(Path.of("")).toString(); String updatedModuleName = packageName + ProjectConstants.DOT + moduleName; Path updatedModulePath = moduleRootPath.resolve(updatedModuleName); return updatedModulePath.resolve(pathInsideModule); @@ -456,7 +494,7 @@ private ModuleDependency createModuleDependencyEntry(Package pkg, } private Path getIconPath(String icon) { - Path iconPath = Paths.get(icon); + Path iconPath = Path.of(icon); if (!iconPath.isAbsolute()) { iconPath = this.packageContext.project().sourceRoot().resolve(iconPath); } @@ -483,7 +521,7 @@ protected void putDirectoryToZipFile(Path sourceDir, Path pathInZipFile, ZipOutp putDirectoryToZipFile(sourceDir.resolve(file.getName()), pathInZipFile, out); } else { Path fileNameInBala = - pathInZipFile.resolve(sourceDir.relativize(Paths.get(file.getPath()))); + pathInZipFile.resolve(sourceDir.relativize(Path.of(file.getPath()))); putZipEntry(out, fileNameInBala, new FileInputStream(sourceDir + File.separator + file.getName())); } @@ -506,12 +544,12 @@ private String convertPathSeperator(Path file) { return null; } else { if (File.separatorChar == '\\') { - String replaced = ""; + String replaced; // Following is to evade spotbug issue if file is null - replaced = Optional.ofNullable(file.getFileName()).orElse(Paths.get("")).toString(); + replaced = Optional.ofNullable(file.getFileName()).orElse(Path.of("")).toString(); Path parent = file.getParent(); while (parent != null) { - replaced = parent.getFileName() + "/" + replaced; + replaced = parent.getFileName() + UNIX_FILE_SEPARATOR + replaced; parent = parent.getParent(); } return replaced; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BallerinaToml.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BallerinaToml.java index 048c67307782..8ba326c3684d 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BallerinaToml.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BallerinaToml.java @@ -27,8 +27,8 @@ */ public class BallerinaToml { - private TomlDocumentContext ballerinaTomlContext; - private Package packageInstance; + private final TomlDocumentContext ballerinaTomlContext; + private final Package packageInstance; private BallerinaToml(Package aPackage, TomlDocumentContext ballerinaTomlContext) { this.packageInstance = aPackage; @@ -74,7 +74,7 @@ public BallerinaToml.Modifier modify() { */ public static class Modifier { private TomlDocument tomlDocument; - private Package oldPackage; + private final Package oldPackage; private Modifier(BallerinaToml oldDocument) { this.tomlDocument = oldDocument.tomlDocument(); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Bootstrap.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Bootstrap.java index d2b6e25ba7b7..e4c6a9f15902 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Bootstrap.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Bootstrap.java @@ -22,6 +22,7 @@ import io.ballerina.projects.environment.ResolutionRequest; import io.ballerina.projects.environment.ResolutionResponse; import org.ballerinalang.model.elements.PackageID; +import org.wso2.ballerinalang.compiler.PackageCache; import org.wso2.ballerinalang.compiler.semantics.analyzer.SymbolResolver; import org.wso2.ballerinalang.compiler.semantics.model.SymbolTable; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BPackageSymbol; @@ -238,8 +239,7 @@ private ResolutionRequest toResolutionRequest(PackageID packageID) { } private BPackageSymbol getSymbolFromCache(CompilerContext context, PackageID packageID) { - org.wso2.ballerinalang.compiler.PackageCache pkgCache = - org.wso2.ballerinalang.compiler.PackageCache.getInstance(context); + PackageCache pkgCache = PackageCache.getInstance(context); BLangPackage bLangPackage = pkgCache.get(packageID); if (bLangPackage != null) { return bLangPackage.symbol; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BuildOptions.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BuildOptions.java index 2844ee6637d3..709140908558 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BuildOptions.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BuildOptions.java @@ -24,20 +24,22 @@ */ public class BuildOptions { - private Boolean testReport; - private Boolean codeCoverage; - private Boolean dumpBuildTime; - private Boolean skipTests; - private CompilationOptions compilationOptions; - private String targetDir; - private Boolean enableCache; - private Boolean nativeImage; - private Boolean exportComponentModel; - private String graalVMBuildOptions; + private final Boolean showDependencyDiagnostics; + private final Boolean testReport; + private final Boolean codeCoverage; + private final Boolean dumpBuildTime; + private final Boolean skipTests; + private final CompilationOptions compilationOptions; + private final String targetDir; + private final Boolean enableCache; + private final Boolean nativeImage; + private final Boolean exportComponentModel; + private final String graalVMBuildOptions; BuildOptions(Boolean testReport, Boolean codeCoverage, Boolean dumpBuildTime, Boolean skipTests, CompilationOptions compilationOptions, String targetPath, Boolean enableCache, - Boolean nativeImage, Boolean exportComponentModel, String graalVMBuildOptions) { + Boolean nativeImage, Boolean exportComponentModel, String graalVMBuildOptions, + Boolean showDependencyDiagnostics) { this.testReport = testReport; this.codeCoverage = codeCoverage; this.dumpBuildTime = dumpBuildTime; @@ -48,6 +50,7 @@ public class BuildOptions { this.nativeImage = nativeImage; this.exportComponentModel = exportComponentModel; this.graalVMBuildOptions = graalVMBuildOptions; + this.showDependencyDiagnostics = showDependencyDiagnostics; } @@ -131,6 +134,10 @@ public String graalVMBuildOptions() { return Objects.requireNonNullElse(this.graalVMBuildOptions, ""); } + public boolean showDependencyDiagnostics() { + return toBooleanDefaultIfNull(this.showDependencyDiagnostics); + } + /** * Merge the given build options by favoring theirs if there are conflicts. * @@ -184,6 +191,11 @@ public BuildOptions acceptTheirs(BuildOptions theirOptions) { } else { buildOptionsBuilder.setGraalVMBuildOptions(this.graalVMBuildOptions); } + if (theirOptions.showDependencyDiagnostics != null) { + buildOptionsBuilder.setShowDependencyDiagnostics(theirOptions.showDependencyDiagnostics); + } else { + buildOptionsBuilder.setShowDependencyDiagnostics(this.showDependencyDiagnostics); + } CompilationOptions compilationOptions = this.compilationOptions.acceptTheirs(theirOptions.compilationOptions()); buildOptionsBuilder.setOffline(compilationOptions.offlineBuild); @@ -200,6 +212,7 @@ public BuildOptions acceptTheirs(BuildOptions theirOptions) { buildOptionsBuilder.setExportComponentModel(compilationOptions.exportComponentModel); buildOptionsBuilder.setEnableCache(compilationOptions.enableCache); buildOptionsBuilder.setRemoteManagement(compilationOptions.remoteManagement); + buildOptionsBuilder.setOptimizeDependencyCompilation(compilationOptions.optimizeDependencyCompilation); return buildOptionsBuilder.build(); } @@ -237,7 +250,9 @@ public enum OptionName { TARGET_DIR("targetDir"), NATIVE_IMAGE("graalvm"), EXPORT_COMPONENT_MODEL("exportComponentModel"), - GRAAL_VM_BUILD_OPTIONS("graalvmBuildOptions"); + GRAAL_VM_BUILD_OPTIONS("graalvmBuildOptions"), + SHOW_DEPENDENCY_DIAGNOSTICS("showDependencyDiagnostics"), + OPTIMIZE_DEPENDENCY_COMPILATION("optimizeDependencyCompilation"); private final String name; @@ -268,7 +283,7 @@ public static class BuildOptionsBuilder { private Boolean nativeImage; private Boolean exportComponentModel; private String graalVMBuildOptions; - + private Boolean showDependencyDiagnostics; private BuildOptionsBuilder() { compilationOptionsBuilder = CompilationOptions.builder(); @@ -397,10 +412,27 @@ public BuildOptionsBuilder setRemoteManagement(Boolean value) { return this; } + public BuildOptionsBuilder setShowDependencyDiagnostics(Boolean value) { + showDependencyDiagnostics = value; + return this; + } + + /** + * (Experimental) option to specify that the memory usage must be optimized. + * + * @param value true or false (default) + * @return BuildOptionsBuilder instance + */ + public BuildOptionsBuilder setOptimizeDependencyCompilation(Boolean value) { + compilationOptionsBuilder.setOptimizeDependencyCompilation(value); + return this; + } + public BuildOptions build() { CompilationOptions compilationOptions = compilationOptionsBuilder.build(); return new BuildOptions(testReport, codeCoverage, dumpBuildTime, skipTests, compilationOptions, - targetPath, enableCache, nativeImage, exportComponentModel, graalVMBuildOptions); + targetPath, enableCache, nativeImage, exportComponentModel, graalVMBuildOptions, + showDependencyDiagnostics); } } } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BuildToolResolution.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BuildToolResolution.java index 0aad4c38894c..12c5a832f77e 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BuildToolResolution.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/BuildToolResolution.java @@ -31,7 +31,6 @@ import org.ballerinalang.central.client.exceptions.CentralClientException; import org.ballerinalang.central.client.model.ToolResolutionCentralRequest; import org.ballerinalang.central.client.model.ToolResolutionCentralResponse; -import org.ballerinalang.toml.exceptions.SettingsTomlException; import org.wso2.ballerinalang.util.RepoUtils; import java.util.ArrayList; @@ -227,17 +226,13 @@ private ToolResolutionCentralRequest createToolResolutionRequests(Set getToolResolutionResponse(ToolResolutionCentralRequest toolResolutionRequest) throws CentralClientException { Settings settings; - try { - settings = RepoUtils.readSettings(); - } catch (SettingsTomlException e) { - settings = Settings.from(); - } + settings = RepoUtils.readSettings(); CentralAPIClient client = new CentralAPIClient(RepoUtils.getRemoteRepoURL(), initializeProxy(settings.getProxy()), settings.getProxy().username(), settings.getProxy().password(), getAccessTokenOfCLI(settings), settings.getCentral().getConnectTimeout(), settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(), - settings.getCentral().getCallTimeout()); + settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries()); String supportedPlatform = Arrays.stream(JvmTarget.values()) .map(JvmTarget::code) .collect(Collectors.joining(",")); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CloudToml.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CloudToml.java index c37a6f1a1f0b..cd20a3c42939 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CloudToml.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CloudToml.java @@ -27,8 +27,8 @@ * @since 2.0.0 */ public class CloudToml { - private TomlDocumentContext cloudTomlContext; - private Package packageInstance; + private final TomlDocumentContext cloudTomlContext; + private final Package packageInstance; private CloudToml(Package aPackage, TomlDocumentContext cloudTomlContext) { this.packageInstance = aPackage; @@ -74,7 +74,7 @@ public CloudToml.Modifier modify() { */ public static class Modifier { private TomlDocument tomlDocument; - private Package oldPackage; + private final Package oldPackage; private Modifier(CloudToml oldDocument) { this.tomlDocument = oldDocument.tomlDocument(); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CodeGeneratorManager.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CodeGeneratorManager.java index 65267bcadd4c..1e08e766c59e 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CodeGeneratorManager.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CodeGeneratorManager.java @@ -333,6 +333,7 @@ public void addTestSourceFile(TextDocument textDocument, String filenamePrefix) } @Override + @Deprecated(since = "2201.10.0", forRemoval = true) public void addResourceFile(byte[] content, String fileName, ModuleId moduleId) { if (currentPackage.moduleIds().contains(moduleId)) { resourceFiles.add(new GeneratedResourceFile(content, fileName, moduleId)); @@ -343,11 +344,13 @@ public void addResourceFile(byte[] content, String fileName, ModuleId moduleId) } @Override + @Deprecated(since = "2201.10.0", forRemoval = true) public void addResourceFile(byte[] content, String fileName) { addResourceFile(content, fileName, defaultModuleId); } @Override + @Deprecated(since = "2201.10.0", forRemoval = true) public void addTestResourceFile(byte[] content, String fileName, ModuleId moduleId) { if (currentPackage.moduleIds().contains(moduleId)) { testResourceFiles.add(new GeneratedTestResourceFile(content, fileName, moduleId)); @@ -358,6 +361,7 @@ public void addTestResourceFile(byte[] content, String fileName, ModuleId module } @Override + @Deprecated(since = "2201.10.0", forRemoval = true) public void addTestResourceFile(byte[] content, String fileName) { addTestResourceFile(content, fileName, defaultModuleId); } @@ -646,11 +650,13 @@ CodeGeneratorTaskResultBuilder addTestSourceFiles(Collection return this; } + @Deprecated(since = "2201.10.0", forRemoval = true) CodeGeneratorTaskResultBuilder addResourceFiles(Collection resourceFiles) { generatedResourceFiles.addAll(resourceFiles); return this; } + @Deprecated(since = "2201.10.0", forRemoval = true) CodeGeneratorTaskResultBuilder addTestResourceFiles(Collection testResourceFiles) { generatedTestResourceFiles.addAll(testResourceFiles); return this; @@ -749,6 +755,7 @@ private Package modifyModule(ModuleId moduleId, Package pkg, CodeGenTaskResult c return modifier.apply().packageInstance(); } + @Deprecated(since = "2201.10.0", forRemoval = true) private void addGeneratedResource(String newResourceFilename, byte[] content, Module.Modifier modifier, @@ -758,6 +765,7 @@ private void addGeneratedResource(String newResourceFilename, modifier.addResource(resourceConfig); } + @Deprecated(since = "2201.10.0", forRemoval = true) private void addGeneratedTestResource(String newTestResourceFilename, byte[] content, Module.Modifier modifier, diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilationOptions.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilationOptions.java index a7214a614199..31b5a927fa2e 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilationOptions.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilationOptions.java @@ -40,13 +40,14 @@ public class CompilationOptions { Boolean enableCache; Boolean disableSyntaxTree; Boolean remoteManagement; + Boolean optimizeDependencyCompilation; CompilationOptions(Boolean offlineBuild, Boolean observabilityIncluded, Boolean dumpBir, Boolean dumpBirFile, String cloud, Boolean listConflictedClasses, Boolean sticky, Boolean dumpGraph, Boolean dumpRawGraphs, Boolean withCodeGenerators, Boolean withCodeModifiers, Boolean configSchemaGen, Boolean exportOpenAPI, Boolean exportComponentModel, Boolean enableCache, Boolean disableSyntaxTree, - Boolean remoteManagement) { + Boolean remoteManagement, Boolean optimizeDependencyCompilation) { this.offlineBuild = offlineBuild; this.observabilityIncluded = observabilityIncluded; this.dumpBir = dumpBir; @@ -64,6 +65,7 @@ public class CompilationOptions { this.enableCache = enableCache; this.disableSyntaxTree = disableSyntaxTree; this.remoteManagement = remoteManagement; + this.optimizeDependencyCompilation = optimizeDependencyCompilation; } public boolean offlineBuild() { @@ -130,6 +132,10 @@ boolean remoteManagement() { return toBooleanDefaultIfNull(this.remoteManagement); } + boolean optimizeDependencyCompilation() { + return toBooleanDefaultIfNull(this.optimizeDependencyCompilation); + } + /** * Merge the given compilation options by favoring theirs if there are conflicts. * @@ -218,6 +224,11 @@ CompilationOptions acceptTheirs(CompilationOptions theirOptions) { } else { compilationOptionsBuilder.setRemoteManagement(this.remoteManagement); } + if (theirOptions.optimizeDependencyCompilation != null) { + compilationOptionsBuilder.setOptimizeDependencyCompilation(theirOptions.optimizeDependencyCompilation); + } else { + compilationOptionsBuilder.setOptimizeDependencyCompilation(this.optimizeDependencyCompilation); + } return compilationOptionsBuilder.build(); } @@ -273,6 +284,7 @@ public static class CompilationOptionsBuilder { private Boolean enableCache; private Boolean disableSyntaxTree; private Boolean remoteManagement; + private Boolean optimizeDependencyCompilation; public CompilationOptionsBuilder setOffline(Boolean value) { offline = value; @@ -359,11 +371,17 @@ public CompilationOptionsBuilder setRemoteManagement(Boolean value) { return this; } + public CompilationOptionsBuilder setOptimizeDependencyCompilation(Boolean value) { + optimizeDependencyCompilation = value; + return this; + } + public CompilationOptions build() { return new CompilationOptions(offline, observabilityIncluded, dumpBir, dumpBirFile, cloud, listConflictedClasses, sticky, dumpGraph, dumpRawGraph, withCodeGenerators, withCodeModifiers, configSchemaGen, exportOpenAPI, - exportComponentModel, enableCache, disableSyntaxTree, remoteManagement); + exportComponentModel, enableCache, disableSyntaxTree, remoteManagement, + optimizeDependencyCompilation); } } } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerBackend.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerBackend.java index 794134edfba1..548e78c8e957 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerBackend.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerBackend.java @@ -68,6 +68,8 @@ public abstract Collection platformLibraryDependencies(PackageI */ public abstract PlatformLibrary codeGeneratedTestLibrary(PackageId packageId, ModuleName moduleName); + public abstract PlatformLibrary codeGeneratedResourcesLibrary(PackageId packageId); + /** * Returns the platform-specific runtime library. * diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerLifecycleManager.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerLifecycleManager.java index b54cb69c12c4..6e321affe9be 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerLifecycleManager.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerLifecycleManager.java @@ -64,9 +64,9 @@ private static LifecycleTasks initLifecycleListeners(List runCodeGeneratedTasks(Path binaryPath) { + public List runCodeGeneratedTasks(Path binaryPath, BalCommand balCommand) { CompilerLifecycleEventContextImpl lifecycleEventContext = - new CompilerLifecycleEventContextImpl(this.currentPackage, this.compilation); + new CompilerLifecycleEventContextImpl(this.currentPackage, this.compilation, balCommand); lifecycleEventContext.setBinaryPath(binaryPath); for (List taskList : lifecycleTasks.codeGenerationCompletedTasks.values()) { @@ -157,8 +157,8 @@ public void addCodeGenerationCompletedTask(LifecycleListenerInfo lifecycleListen static class CodeGenerationCompletedTask { - private CompilerLifecycleTask lifecycleTask; - private LifecycleListenerInfo lifecycleListenerInfo; + private final CompilerLifecycleTask lifecycleTask; + private final LifecycleListenerInfo lifecycleListenerInfo; public CodeGenerationCompletedTask(CompilerLifecycleTask lifecycleTask, LifecycleListenerInfo lifecycleListenerInfo) { @@ -191,12 +191,16 @@ private static class CompilerLifecycleEventContextImpl implements CompilerLifecy private final Package currentPackage; private final PackageCompilation compilation; + private final BalCommand balCommand; + private Path binaryPath; private final List diagnostics = new ArrayList<>(); - public CompilerLifecycleEventContextImpl(Package currentPackage, PackageCompilation compilation) { + public CompilerLifecycleEventContextImpl(Package currentPackage, PackageCompilation compilation, + BalCommand balCommand) { this.currentPackage = currentPackage; this.compilation = compilation; + this.balCommand = balCommand; } @Override @@ -214,6 +218,11 @@ public void reportDiagnostic(Diagnostic diagnostic) { diagnostics.add(diagnostic); } + @Override + public BalCommand balCommand() { + return balCommand; + } + void setBinaryPath(Path binaryPath) { this.binaryPath = binaryPath; } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginContextIml.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginContextIml.java index efc2a86bec46..b3d1ba54f6d4 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginContextIml.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginContextIml.java @@ -17,6 +17,7 @@ */ package io.ballerina.projects; +import io.ballerina.compiler.syntax.tree.Node; import io.ballerina.projects.plugins.CodeAnalyzer; import io.ballerina.projects.plugins.CodeGenerator; import io.ballerina.projects.plugins.CodeModifier; @@ -43,8 +44,8 @@ class CompilerPluginContextIml implements CompilerPluginContext { private final List codeModifiers = new ArrayList<>(); private final List lifecycleListeners = new ArrayList<>(); private final List codeActions = new ArrayList<>(); - private Map compilerPluginUserData = new HashMap(); - private final List completionProviders = new ArrayList<>(); + private Map compilerPluginUserData = new HashMap<>(); + private final List> completionProviders = new ArrayList<>(); CompilerPluginContextIml(CompilerPluginInfo compilerPluginInfo) { this.compilerPluginInfo = compilerPluginInfo; @@ -55,14 +56,17 @@ class CompilerPluginContextIml implements CompilerPluginContext { this.compilerPluginUserData = userData; } + @Override public void addCodeAnalyzer(CodeAnalyzer codeAnalyzer) { codeAnalyzers.add(new CodeAnalyzerManager.CodeAnalyzerInfo(codeAnalyzer, compilerPluginInfo)); } + @Override public void addCodeGenerator(CodeGenerator codeGenerator) { codeGenerators.add(new CodeGeneratorManager.CodeGeneratorInfo(codeGenerator, compilerPluginInfo)); } + @Override public void addCodeModifier(CodeModifier codeModifier) { codeModifiers.add(new CodeModifierManager.CodeModifierInfo(codeModifier, compilerPluginInfo)); } @@ -79,7 +83,7 @@ public void addCodeAction(CodeAction codeAction) { } @Override - public void addCompletionProvider(CompletionProvider completionProvider) { + public void addCompletionProvider(CompletionProvider completionProvider) { completionProviders.add(completionProvider); } @@ -103,7 +107,7 @@ public List codeActions() { return codeActions; } - public List completionProviders() { + public List> completionProviders() { return completionProviders; } @@ -111,6 +115,7 @@ public CompilerPluginInfo compilerPluginInfo() { return compilerPluginInfo; } + @Override public Map userData() { return this.compilerPluginUserData; } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginKind.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginKind.java index a23a0d2f833f..8741732d96ce 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginKind.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginKind.java @@ -28,5 +28,4 @@ enum CompilerPluginKind { BUILT_IN, PACKAGE_PROVIDED, - ; } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginManager.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginManager.java index 7a946223b7e0..25b64409b3ce 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginManager.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginManager.java @@ -22,11 +22,9 @@ import io.ballerina.projects.plugins.CompilerPlugin; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; /** * Responsible for loading and maintaining engaged compiler plugins. @@ -51,6 +49,12 @@ private CompilerPluginManager(PackageCompilation compilation, } static CompilerPluginManager from(PackageCompilation compilation) { + // Skip initialization if the compiler plugins are already initialized for the project + if (!compilation.packageContext().project().compilerPluginContexts().isEmpty()) { + List compilerPluginContexts = + compilation.packageContext().project().compilerPluginContexts(); + return new CompilerPluginManager(compilation, compilerPluginContexts); + } // TODO We need to update the DependencyGraph API. Right now it is a mess PackageResolution packageResolution = compilation.getResolution(); ResolvedPackageDependency rootPkgNode = new ResolvedPackageDependency( @@ -164,8 +168,8 @@ private static CompilerPluginInfo loadCompilerPlugin(CompilerPluginDescriptor pl String pluginClassName = pluginDescriptor.plugin().getClassName(); List jarLibraryPaths = pluginDescriptor.getCompilerPluginDependencies() .stream() - .map(Paths::get) - .collect(Collectors.toList()); + .map(Path::of) + .toList(); CompilerPlugin compilerPlugin; try { @@ -186,15 +190,11 @@ private static List getDirectDependencies(ResolvedPackageDependency roo return dependencyGraph.getDirectDependencies(rootPkgNode) .stream() .map(ResolvedPackageDependency::packageInstance) - .collect(Collectors.toList()); + .toList(); } private static List initializePlugins(List compilerPlugins, PackageCompilation compilation) { - // Skip initialization if the compiler plugins are already initialized for the project - if (!compilation.packageContext().project().compilerPluginContexts().isEmpty()) { - return compilation.packageContext().project().compilerPluginContexts(); - } List compilerPluginContexts = new ArrayList<>(compilerPlugins.size()); for (CompilerPluginInfo compilerPluginInfo : compilerPlugins) { CompilerPluginCache pluginCache = diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginToml.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginToml.java index a05da32ef41a..2f98c0432230 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginToml.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompilerPluginToml.java @@ -9,8 +9,8 @@ * @since 2.0.0 */ public class CompilerPluginToml { - private TomlDocumentContext compilerPluginTomlContext; - private Package packageInstance; + private final TomlDocumentContext compilerPluginTomlContext; + private final Package packageInstance; private CompilerPluginToml(TomlDocumentContext compilerPluginTomlContext, Package packageInstance) { this.compilerPluginTomlContext = compilerPluginTomlContext; @@ -55,7 +55,7 @@ public CompilerPluginToml.Modifier modify() { */ public static class Modifier { private TomlDocument tomlDocument; - private Package oldPackage; + private final Package oldPackage; private Modifier(CompilerPluginToml oldDocument) { this.tomlDocument = oldDocument.tomlDocument(); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompletionManager.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompletionManager.java index ba53edad7e5f..f25c62f21e86 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompletionManager.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/CompletionManager.java @@ -41,7 +41,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.stream.Collectors; /** * Manages interaction with completion providers via compiler plugins. @@ -54,11 +53,13 @@ public class CompletionManager { private CompletionManager(List compilerPluginContexts) { completionProviders = new HashMap<>(); compilerPluginContexts.forEach(compilerPluginContextIml -> { - for (CompletionProvider completionProvider : compilerPluginContextIml.completionProviders()) { + for (CompletionProvider completionProvider : + compilerPluginContextIml.completionProviders()) { for (Class attachmentPoint : completionProvider.getSupportedNodes()) { List completionProviderList = completionProviders.computeIfAbsent(attachmentPoint, k -> new ArrayList<>()); - completionProviderList.add(new CompletionProviderDescriptor(completionProvider, + completionProviderList.add(new CompletionProviderDescriptor( + (CompletionProvider) completionProvider, compilerPluginContextIml.compilerPluginInfo())); } } @@ -159,7 +160,7 @@ private List getModulesOfActiveListeners(CompletionContext context } return Optional.of(listenerType); }).filter(listenerType -> listenerType.isPresent() && listenerType.get().getModule().isPresent()) - .map(listenerType -> listenerType.get().getModule().get()).collect(Collectors.toList()); + .map(listenerType -> listenerType.get().getModule().get()).toList(); } private TypeSymbol getRawType(TypeSymbol typeDescriptor) { @@ -204,7 +205,7 @@ static class CompletionProviderDescriptor { private final CompletionProvider completionProvider; private final CompilerPluginInfo compilerPluginInfo; - public CompletionProviderDescriptor(CompletionProvider completionProvider, + public CompletionProviderDescriptor(CompletionProvider completionProvider, CompilerPluginInfo compilerPluginInfo) { this.completionProvider = completionProvider; this.compilerPluginInfo = compilerPluginInfo; @@ -225,7 +226,7 @@ public CompilerPluginInfo compilerPluginInfo() { */ static class ServiceDeclarationContextValidator extends NodeVisitor { - private CompletionContext context; + private final CompletionContext context; private boolean isValidContext = false; public ServiceDeclarationContextValidator(CompletionContext context) { diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ConfigReader.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ConfigReader.java index 68da8a05610c..fc35b719b2de 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ConfigReader.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ConfigReader.java @@ -26,7 +26,6 @@ import io.ballerina.compiler.syntax.tree.ModulePartNode; import io.ballerina.compiler.syntax.tree.ModuleVariableDeclarationNode; import io.ballerina.compiler.syntax.tree.Node; -import io.ballerina.compiler.syntax.tree.NodeList; import io.ballerina.compiler.syntax.tree.SimpleNameReferenceNode; import io.ballerina.compiler.syntax.tree.SpecificFieldNode; import io.ballerina.compiler.syntax.tree.SyntaxKind; @@ -44,23 +43,26 @@ import org.wso2.ballerinalang.util.Flags; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; /** * Util class to read configurable variables defined in a package. * * @since 2.0.0 */ -public class ConfigReader { +public final class ConfigReader { + + private ConfigReader() { + } /** - * Retrieve configurable variables in a package as a per module map. + * Retrieve all the configurable variables for a package. * * @param packageInstance to read configurable variables * @return A map with ConfigModuleDetails(module details) as key and @@ -68,19 +70,112 @@ public class ConfigReader { */ public static Map> getConfigVariables(Package packageInstance) { Map> configDetails = new HashMap<>(); + // Get configurable variables of the current package Set validConfigs = getValidConfigs(packageInstance.getDefaultModule().moduleContext(). bLangPackage().symbol); for (Module module : packageInstance.modules()) { getConfigs(module, module.moduleContext().bLangPackage(), configDetails, validConfigs); } + // Get configurable variables of the direct imports + Collection dependencies = new ArrayList<>(); + getValidDependencies(packageInstance, packageInstance.getDefaultModule(), dependencies); + getImportedConfigVars(packageInstance, dependencies, configDetails); return configDetails; } + /** + * Retrieve configurable variables for all the direct imports for a package. + * + * @param currentPackage Current package instance + * @param moduleDependencies Used dependencies of the package + * @param configDetails Map to store the configurable variables against module + */ + private static void getImportedConfigVars(Package currentPackage, + Collection moduleDependencies, + Map> configDetails) { + currentPackage.modules().forEach(module -> + module.moduleContext().bLangPackage().symbol.imports.stream() + .filter(importSymbol -> isDirectDependency( + moduleDependencies, + importSymbol.descriptor.org().value(), + importSymbol.descriptor.packageName().value(), + importSymbol.descriptor.name().moduleNamePart() + )) + .forEach(importSymbol -> { + String orgName = importSymbol.descriptor.org().value(); + String packageName = importSymbol.descriptor.packageName().value(); + String moduleName = importSymbol.descriptor.name().moduleNamePart(); + + // If default module + if (moduleName == null) { + moduleName = packageName; + } + + List configVariables = new ArrayList<>(); + getConfigVars(module, importSymbol.scope.entries.values(), null, configVariables); + + if (!configVariables.isEmpty()) { + configDetails.put( + new ConfigModuleDetails(orgName, packageName, moduleName, + ProjectKind.BALA_PROJECT), configVariables); + } + }) + ); + } + + /** + * Checks whether it is a direct dependency. + * + * @param moduleDependencies collection of module dependencies + * @param orgName org name + * @param packageName package name + * @param moduleName module name + * @return boolean value indicating whether it is a direct dependency + */ + private static boolean isDirectDependency(Collection moduleDependencies, String orgName, + String packageName, String moduleName) { + return moduleDependencies.stream().anyMatch(dependency -> + dependency.descriptor().org().value().equals(orgName) && + dependency.descriptor().packageName().value().equals(packageName) && + (moduleName == null + ? dependency.descriptor().name().moduleNamePart() == null + : moduleName.equals(dependency.descriptor().name().moduleNamePart())) + ); + } + + private static String getDescriptionValue(MetadataNode metadataNode) { + for (AnnotationNode annotation : metadataNode.annotations()) { + Node annotReference = annotation.annotReference(); + if (annotReference.kind() == SyntaxKind.SIMPLE_NAME_REFERENCE && + ((SimpleNameReferenceNode) annotReference).name().text().equals("display") && + annotation.annotValue().isPresent()) { + + for (MappingFieldNode fieldNode : annotation.annotValue().get().fields()) { + if (fieldNode.kind() == SyntaxKind.SPECIFIC_FIELD) { + SpecificFieldNode specificField = (SpecificFieldNode) fieldNode; + if (specificField.fieldName().kind() == SyntaxKind.IDENTIFIER_TOKEN && + ((IdentifierToken) specificField.fieldName()).text().equals("description") && + specificField.valueExpr().isPresent()) { + + ExpressionNode valueNode = specificField.valueExpr().get(); + if (valueNode instanceof BasicLiteralNode) { + return ((BasicLiteralNode) valueNode).literalToken().text(); + } + } + } + } + } + } + return ""; + } + + + /** * Update provided map with the configurable variable details for the given module. * - * @param module Module to retrieve module details - * @param bLangPackage to retrieve configurable variable details + * @param module Module to retrieve module details + * @param bLangPackage to retrieve configurable variable details * @param configDetails Map to store the configurable variables against module */ private static void getConfigs(Module module, @@ -88,32 +183,40 @@ private static void getConfigs(Module module, List> configDetails, Set validConfigs) { List configVariables = new ArrayList<>(); PackageID currentPkgId = bLangPackage.symbol.pkgID; - for (Scope.ScopeEntry entry : bLangPackage.symbol.scope.entries.values()) { + getConfigVars(module, bLangPackage.symbol.scope.entries.values(), validConfigs, configVariables); + if (!configVariables.isEmpty()) { + // Add configurable variable details for the current package + configDetails.put(getConfigModuleDetails(module.moduleName(), currentPkgId, + module.project().kind()), configVariables); + } + } + + private static void getConfigVars(Module module, Collection scopeEntries, + Set validConfigs, List configVariables) { + for (Scope.ScopeEntry entry : scopeEntries) { BSymbol symbol = entry.symbol; // Filter configurable variables if (symbol != null && symbol.tag == SymTag.VARIABLE && Symbols.isFlagOn(symbol.flags, Flags.CONFIGURABLE)) { - if (symbol instanceof BVarSymbol) { - BVarSymbol varSymbol = (BVarSymbol) symbol; - if (validConfigs.contains(varSymbol)) { + if (symbol instanceof BVarSymbol varSymbol) { + if ((validConfigs != null && validConfigs.contains(varSymbol)) || validConfigs == null) { // Get description - String description = getDescription(varSymbol, module); - if (description.startsWith("\"") && description.endsWith("\"")) { - description = description.substring(1, description.length() - 1); - } - configVariables.add(new ConfigVariable(varSymbol.name.value.replace("\\", ""), varSymbol.type, + String description = getDescriptionValue(varSymbol, module); + configVariables.add(new ConfigVariable( + varSymbol.name.value.replace("\\", ""), varSymbol.type, Symbols.isFlagOn(varSymbol.flags, Flags.REQUIRED), description)); } } } } - if (!configVariables.isEmpty()) { - // Add configurable variable details for the current package - configDetails.put(getConfigModuleDetails(module.moduleName(), currentPkgId, - module.project().kind()), configVariables); - } } + /** + * Get the used configurable variables of the package. + * + * @param packageSymbol ballerina package symbol + * @return set of valid configurable variable symbols + */ private static Set getValidConfigs(BPackageSymbol packageSymbol) { Set configVars = new HashSet<>(); populateConfigVars(packageSymbol, configVars); @@ -125,6 +228,12 @@ private static Set getValidConfigs(BPackageSymbol packageSymbol) { return configVars; } + /** + * Populate the configurable variables for the package. + * + * @param pkgSymbol ballerina package symbol + * @param configVars set of configurable variable symbols + */ private static void populateConfigVars(BPackageSymbol pkgSymbol, Set configVars) { for (Scope.ScopeEntry entry : pkgSymbol.scope.entries.values()) { BSymbol symbol = entry.symbol; @@ -133,8 +242,9 @@ private static void populateConfigVars(BPackageSymbol pkgSymbol, Set symbol = symbol.type.tsymbol; } if (symbol != null && symbol.tag == SymTag.VARIABLE - && Symbols.isFlagOn(symbol.flags, Flags.CONFIGURABLE) && symbol instanceof BVarSymbol) { - configVars.add((BVarSymbol) symbol); + && Symbols.isFlagOn(symbol.flags, Flags.CONFIGURABLE) && + symbol instanceof BVarSymbol bVarSymbol) { + configVars.add(bVarSymbol); } } } @@ -143,8 +253,8 @@ private static void populateConfigVars(BPackageSymbol pkgSymbol, Set /** * Get module details to store the configurable variables against. * - * @param moduleName to retrieve module details - * @param packageID to retrieve package details + * @param moduleName to retrieve module details + * @param packageID to retrieve package details * @param projectKind to retrieve information about the type of project * @return module details stored in object ConfigModuleDetails */ @@ -163,40 +273,19 @@ private static ConfigModuleDetails getConfigModuleDetails(ModuleName moduleName, * @param module to retrieve module details * @return configurable variable description */ - private static String getDescription(BVarSymbol symbol, Module module) { + private static String getDescriptionValue(BVarSymbol symbol, Module module) { Map syntaxTreeMap = getSyntaxTreeMap(module); Node variableNode = getVariableNode(symbol.getPosition().lineRange().startLine().line(), syntaxTreeMap); if (variableNode != null) { Optional optionalMetadataNode = ((ModuleVariableDeclarationNode) variableNode).metadata(); if (optionalMetadataNode.isPresent()) { - NodeList annotations = optionalMetadataNode.get().annotations(); - for (AnnotationNode annotation : annotations) { - Node annotReference = annotation.annotReference(); - if (annotReference.kind() == SyntaxKind.SIMPLE_NAME_REFERENCE) { - SimpleNameReferenceNode simpleNameRef = (SimpleNameReferenceNode) annotReference; - if (simpleNameRef.name().text().equals("display") && annotation.annotValue().isPresent()) { - for (MappingFieldNode fieldNode : annotation.annotValue().get().fields()) { - if (fieldNode.kind() == SyntaxKind.SPECIFIC_FIELD) { - SpecificFieldNode specificField = (SpecificFieldNode) fieldNode; - if (specificField.fieldName().kind() == SyntaxKind.IDENTIFIER_TOKEN) { - if (((IdentifierToken) specificField.fieldName()).text(). - equals("description")) { - if (((SpecificFieldNode) fieldNode).valueExpr().isPresent()) { - ExpressionNode valueNode = - ((SpecificFieldNode) fieldNode).valueExpr().get(); - if (valueNode instanceof BasicLiteralNode) { - return ((BasicLiteralNode) valueNode).literalToken().text(); - } - } - } - } - } - - } - } - } + String description = getDescriptionValue(optionalMetadataNode.get()); + // Remove enclosing quotes if present + if (description.startsWith("\"") && description.endsWith("\"")) { + description = description.substring(1, description.length() - 1); } + return description; } } return ""; @@ -205,7 +294,7 @@ private static String getDescription(BVarSymbol symbol, Module module) { /** * Get Syntax tree node for the configurable variable in given position. * - * @param position position of configurable BVarSymbol + * @param position position of configurable BVarSymbol * @param syntaxTreeMap Syntax tree map for the specific module * @return Relevant syntax tree node for the variable */ @@ -213,16 +302,13 @@ private static Node getVariableNode(int position, Map synt for (Map.Entry syntaxTreeEntry : syntaxTreeMap.entrySet()) { if (syntaxTreeEntry.getValue().containsModulePart()) { ModulePartNode modulePartNode = syntaxTreeMap.get(syntaxTreeEntry.getKey()).rootNode(); - List filteredVarNodes = modulePartNode.members().stream() - .filter(node -> node.kind() == SyntaxKind.MODULE_VAR_DECL && - node instanceof ModuleVariableDeclarationNode) - .collect(Collectors.toList()); - for (Node node : filteredVarNodes) { - if (node.location().lineRange().startLine().line() <= position && - node.location().lineRange().endLine().line() >= position) { - return node; - } - } + return modulePartNode.members().stream() + .filter(node -> node.kind() == SyntaxKind.MODULE_VAR_DECL && + node instanceof ModuleVariableDeclarationNode && + node.location().lineRange().startLine().line() <= position && + node.location().lineRange().endLine().line() >= position) + .findFirst() + .orElse(null); } } return null; @@ -243,4 +329,56 @@ private static Map getSyntaxTreeMap(Module module) { return syntaxTreeMap; } + /** + * Get all the valid dependencies for the package. + * + * @param packageInstance Package instance + * @param module module instance + * @param dependencies Collection of module dependencies + */ + private static void getValidDependencies(Package packageInstance, Module module, + Collection dependencies) { + Collection directDependencies = module.moduleContext().dependencies(); + for (ModuleDependency moduleDependency : directDependencies) { + if (!isDefaultScope(moduleDependency)) { + continue; + } + dependencies.add(moduleDependency); + if (isSamePackage(packageInstance, moduleDependency)) { + for (Module mod : packageInstance.modules()) { + String modName = mod.descriptor().name().moduleNamePart(); + if (modName != null && modName.equals( + moduleDependency.descriptor().name().moduleNamePart())) { + getValidDependencies(packageInstance, mod, dependencies); + } + } + } + } + } + + /** + * Check if the dependency has the default scope. + * + * @param moduleDependency Module dependency + * @return boolean value indicating whether the dependency has default scope or not + */ + private static boolean isDefaultScope(ModuleDependency moduleDependency) { + return moduleDependency.packageDependency().scope().getValue().equals( + PlatformLibraryScope.DEFAULT.getStringValue()); + } + + /** + * Check if the dependency is From the same package. + * + * @param packageInstance package instance + * @param moduleDependency Module dependency + * @return boolean value indicating whether the dependency is from the same package or not + */ + private static boolean isSamePackage(Package packageInstance, ModuleDependency moduleDependency) { + String orgValue = moduleDependency.descriptor().org().value(); + String packageVal = moduleDependency.descriptor().packageName().value(); + return orgValue.equals(packageInstance.packageOrg().value()) && + packageVal.equals(packageInstance.packageName().value()); + } + } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/DependenciesToml.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/DependenciesToml.java index fda74d112167..5ea63acca814 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/DependenciesToml.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/DependenciesToml.java @@ -27,8 +27,8 @@ * @since 2.0.0 */ public class DependenciesToml { - private TomlDocumentContext dependenciesTomlContext; - private Package packageInstance; + private final TomlDocumentContext dependenciesTomlContext; + private final Package packageInstance; private DependenciesToml(Package aPackage, TomlDocumentContext dependenciesTomlContext) { this.packageInstance = aPackage; @@ -72,7 +72,7 @@ public DependenciesToml.Modifier modify() { */ public static class Modifier { private TomlDocument tomlDocument; - private Package oldPackage; + private final Package oldPackage; private Modifier(DependenciesToml oldDocument) { this.tomlDocument = oldDocument.tomlDocument(); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Diagnostics.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Diagnostics.java index 15fce09fc326..0f93cd199cd3 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Diagnostics.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Diagnostics.java @@ -22,14 +22,16 @@ import java.util.Collection; import java.util.function.Predicate; -import java.util.stream.Collectors; /** * This class contains various static methods that operate on {@code Diagnostic} instances. * * @since 2.0.0 */ -public class Diagnostics { +public final class Diagnostics { + + private Diagnostics() { + } public static Collection filterErrors(Collection diagnostics) { return filterDiagnostics(diagnostics, DiagnosticSeverity.ERROR); @@ -69,7 +71,7 @@ private static Collection filterDiagnostics(Collection d Predicate predicate) { return diagnostics.stream() .filter(predicate) - .collect(Collectors.toList()); + .toList(); } private static boolean hasDiagnosticsWithSeverity(Collection diagnostics, diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Document.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Document.java index c34c2517ae5c..59d007d56595 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Document.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Document.java @@ -72,9 +72,9 @@ public Modifier modify() { */ public static class Modifier { private String content; - private String name; - private DocumentId documentId; - private Module oldModule; + private final String name; + private final DocumentId documentId; + private final Module oldModule; private Modifier(Document oldDocument) { this.documentId = oldDocument.documentId(); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/DocumentContext.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/DocumentContext.java index b91b222fe5a5..c219679275d7 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/DocumentContext.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/DocumentContext.java @@ -196,6 +196,8 @@ void shrink() { if (this.compilationUnit != null) { this.compilationUnit.topLevelNodes.clear(); } + this.syntaxTree = null; + this.moduleLoadRequests = null; this.content = null; } } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/JBallerinaBackend.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/JBallerinaBackend.java index aecdaeea4012..7f9931d5e2e3 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/JBallerinaBackend.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/JBallerinaBackend.java @@ -22,7 +22,6 @@ import io.ballerina.projects.internal.DefaultDiagnosticResult; import io.ballerina.projects.internal.PackageDiagnostic; import io.ballerina.projects.internal.ProjectDiagnosticErrorCode; -import io.ballerina.projects.internal.jballerina.JarWriter; import io.ballerina.projects.internal.model.Target; import io.ballerina.projects.util.ProjectConstants; import io.ballerina.projects.util.ProjectUtils; @@ -38,8 +37,8 @@ import org.ballerinalang.maven.MavenResolver; import org.ballerinalang.maven.Utils; import org.ballerinalang.maven.exceptions.MavenResolverException; -import org.wso2.ballerinalang.compiler.CompiledJarFile; import org.wso2.ballerinalang.compiler.bir.codegen.CodeGenerator; +import org.wso2.ballerinalang.compiler.bir.codegen.CompiledJarFile; import org.wso2.ballerinalang.compiler.bir.codegen.interop.InteropValidator; import org.wso2.ballerinalang.compiler.tree.BLangPackage; import org.wso2.ballerinalang.compiler.util.CompilerContext; @@ -56,7 +55,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -73,11 +71,12 @@ import java.util.jar.JarFile; import java.util.jar.JarInputStream; import java.util.jar.Manifest; -import java.util.stream.Collectors; import static io.ballerina.projects.util.FileUtils.getFileNameWithoutExtension; import static io.ballerina.projects.util.ProjectConstants.BIN_DIR_NAME; import static io.ballerina.projects.util.ProjectConstants.DOT; +import static io.ballerina.projects.util.ProjectConstants.RESOURCE_DIR_NAME; +import static io.ballerina.projects.util.ProjectUtils.getConflictingResourcesMsg; import static io.ballerina.projects.util.ProjectUtils.getThinJarFileName; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CLASS_FILE_SUFFIX; @@ -95,6 +94,7 @@ public class JBallerinaBackend extends CompilerBackend { private static final String JAR_FILE_NAME_SUFFIX = ""; private static final HashSet excludeExtensions = new HashSet<>(Lists.of("DSA", "SF")); private static final String OS = System.getProperty("os.name").toLowerCase(Locale.getDefault()); + public static final String JAR_NAME_SEPARATOR = "-"; private final PackageResolution pkgResolution; private final JvmTarget jdkVersion; @@ -108,6 +108,7 @@ public class JBallerinaBackend extends CompilerBackend { private DiagnosticResult diagnosticResult; private boolean codeGenCompleted; private final List conflictedJars; + List conflictedResourcesDiagnostics = new ArrayList<>(); public static JBallerinaBackend from(PackageCompilation packageCompilation, JvmTarget jdkVersion) { return from(packageCompilation, jdkVersion, true); @@ -159,6 +160,9 @@ private void performCodeGen(boolean shrink) { // collect compilation diagnostics List moduleDiagnostics = new ArrayList<>(); for (ModuleContext moduleContext : pkgResolution.topologicallySortedModuleList()) { + if (shrink) { + ModuleContext.shrinkDocuments(moduleContext); + } if (moduleContext.moduleId().packageId().equals(packageContext.packageId())) { if (packageCompilation.diagnosticResult().hasErrors()) { for (Diagnostic diagnostic : moduleContext.diagnostics()) { @@ -173,21 +177,25 @@ private void performCodeGen(boolean shrink) { moduleContext.generatePlatformSpecificCode(compilerContext, this); } for (Diagnostic diagnostic : moduleContext.diagnostics()) { - moduleDiagnostics.add( - new PackageDiagnostic(diagnostic, moduleContext.descriptor(), moduleContext.project())); + if (this.packageContext.project().buildOptions().showDependencyDiagnostics() || + !ProjectKind.BALA_PROJECT.equals(moduleContext.project().kind()) || + (diagnostic.diagnosticInfo().severity() == DiagnosticSeverity.ERROR)) { + moduleDiagnostics.add( + new PackageDiagnostic(diagnostic, moduleContext.descriptor(), moduleContext.project())); + } } - if (shrink) { - ModuleContext.shrinkDocuments(moduleContext); - } if (moduleContext.project().kind() == ProjectKind.BALA_PROJECT) { moduleContext.cleanBLangPackage(); } } + // add compilation diagnostics diagnostics.addAll(moduleDiagnostics); // add plugin diagnostics diagnostics.addAll(this.packageContext.getPackageCompilation().pluginDiagnostics()); + // add conflicting resources diagnostics + diagnostics.addAll(conflictedResourcesDiagnostics); this.diagnosticResult = new DefaultDiagnosticResult(diagnostics); codeGenCompleted = true; @@ -221,21 +229,46 @@ public EmitResult emit(OutputType outputType, Path filePath) { default -> throw new RuntimeException("Unexpected output type: " + outputType); }; - ArrayList allDiagnostics = new ArrayList<>(diagnosticResult.allDiagnostics); - // Add lifecycle plugin diagnostics. - List pluginDiagnostics = packageCompilation.notifyCompilationCompletion(filePath); - if (!pluginDiagnostics.isEmpty()) { - emitResultDiagnostics.addAll(pluginDiagnostics); - } - // Add jar resolver diagnostics. - emitResultDiagnostics.addAll(jarResolver().diagnosticResult().diagnostics()); - // JBallerinaBackend diagnostics contains all diagnostics. - // EmitResult will only contain diagnostics related to emitting the executable. - allDiagnostics.addAll(emitResultDiagnostics); + return getEmitResult(filePath, generatedArtifact, BalCommand.BUILD, emitResultDiagnostics); + } + + public EmitResult emit(TestEmitArgs testEmitArgs) { + Path generatedArtifact = null; + + if (diagnosticResult.hasErrors()) { + return new EmitResult(false, new DefaultDiagnosticResult(new ArrayList<>()), null); + } + + if (testEmitArgs.outputType() == OutputType.TEST) { + generatedArtifact = emitTestExecutable(testEmitArgs.filePath(), testEmitArgs.jarDependencies(), + testEmitArgs.testSuiteJsonPath(), testEmitArgs.jsonCopyPath(), + testEmitArgs.excludedClasses(), testEmitArgs.classPathTextCopyPath()); + } else { + throw new RuntimeException("Unexpected output type: " + testEmitArgs.outputType()); + } + + return getEmitResult(testEmitArgs.filePath(), generatedArtifact, BalCommand.TEST, new ArrayList<>()); + } + + private EmitResult getEmitResult(Path filePath, Path generatedArtifact, BalCommand balCommand, + List emitDiagnostics) { + if (filePath != null) { + List pluginDiagnostics = notifyCompilationCompletion(filePath, balCommand); + if (!pluginDiagnostics.isEmpty()) { + emitDiagnostics.addAll(pluginDiagnostics); + } + } + List allDiagnostics = new ArrayList<>(diagnosticResult.allDiagnostics); + emitDiagnostics.addAll(jarResolver().diagnosticResult().diagnostics()); + allDiagnostics.addAll(emitDiagnostics); diagnosticResult = new DefaultDiagnosticResult(allDiagnostics); // TODO handle the EmitResult properly - return new EmitResult(true, new DefaultDiagnosticResult(emitResultDiagnostics), generatedArtifact); + return new EmitResult(true, new DefaultDiagnosticResult(emitDiagnostics), generatedArtifact); + } + + public List notifyCompilationCompletion(Path filePath, BalCommand balCommand) { + return packageCompilation.notifyCompilationCompletion(filePath, balCommand); } private Path emitBala(Path filePath) { @@ -255,7 +288,7 @@ public Collection platformLibraryDependencies(PackageId package return getPlatformLibraries(packageId) .stream() .filter(platformLibrary -> platformLibrary.scope() == scope) - .collect(Collectors.toList()); + .toList(); } private List getPlatformLibraries(PackageId packageId) { @@ -283,7 +316,7 @@ private List getPlatformLibraries(PackageId packageId) { if (Objects.equals(dependencyScope, PlatformLibraryScope.PROVIDED) && !Objects.equals(packageId, this.packageContext().packageId())) { dependencyFilePath = getPlatformLibPathFromProvided(platform, groupId, artifactId, version); - Path jarPath = Paths.get(dependencyFilePath); + Path jarPath = Path.of(dependencyFilePath); if (!jarPath.isAbsolute()) { jarPath = this.packageContext().project().sourceRoot().resolve(jarPath); } @@ -294,7 +327,7 @@ private List getPlatformLibraries(PackageId packageId) { dependency.put(JarLibrary.KEY_PATH, dependencyFilePath); } // If the path is relative we will convert to absolute relative to Ballerina.toml file - Path jarPath = Paths.get(dependencyFilePath); + Path jarPath = Path.of(dependencyFilePath); if (!jarPath.isAbsolute()) { jarPath = pkg.project().sourceRoot().resolve(jarPath); } @@ -316,6 +349,11 @@ public PlatformLibrary codeGeneratedTestLibrary(PackageId packageId, ModuleName TEST_JAR_FILE_NAME_SUFFIX + JAR_FILE_NAME_SUFFIX); } + @Override + public PlatformLibrary codeGeneratedResourcesLibrary(PackageId packageId) { + return codeGeneratedResourcesLibrary(packageId, PlatformLibraryScope.DEFAULT); + } + @Override public PlatformLibrary runtimeLibrary() { return new JarLibrary(ProjectUtils.getBallerinaRTJarPath(), PlatformLibraryScope.DEFAULT); @@ -336,16 +374,17 @@ public void performCodeGen(ModuleContext moduleContext, CompilationCache compila } boolean isRemoteMgtEnabled = moduleContext.project().buildOptions().compilationOptions().remoteManagement(); CompiledJarFile compiledJarFile = jvmCodeGenerator.generate(bLangPackage, isRemoteMgtEnabled); - if (compiledJarFile == null) { - throw new IllegalStateException("Missing generated jar, module: " + moduleContext.moduleName()); - } String jarFileName = getJarFileName(moduleContext) + JAR_FILE_NAME_SUFFIX; try { - ByteArrayOutputStream byteStream = JarWriter.write(compiledJarFile, getResources(moduleContext)); + ByteArrayOutputStream byteStream = compiledJarFile.toByteArrayStream(); compilationCache.cachePlatformSpecificLibrary(this, jarFileName, byteStream); } catch (IOException e) { throw new ProjectException("Failed to cache generated jar, module: " + moduleContext.moduleName()); } + if (moduleContext.project().currentPackage().packageContext() == packageContext && + moduleContext.isDefaultModule()) { + cacheResources(compilationCache, moduleContext.project().buildOptions().skipTests()); + } // skip generation of the test jar if --with-tests option is not provided if (moduleContext.project().buildOptions().skipTests()) { return; @@ -359,7 +398,7 @@ public void performCodeGen(ModuleContext moduleContext, CompilationCache compila CompiledJarFile compiledTestJarFile = jvmCodeGenerator.generateTestModule(bLangPackage.testablePkgs.get(0), isRemoteMgtEnabled); try { - ByteArrayOutputStream byteStream = JarWriter.write(compiledTestJarFile, getAllResources(moduleContext)); + ByteArrayOutputStream byteStream = compiledTestJarFile.toByteArrayStream(); compilationCache.cachePlatformSpecificLibrary(this, testJarFileName, byteStream); } catch (IOException e) { throw new ProjectException("Failed to cache generated test jar, module: " + moduleContext.moduleName()); @@ -410,23 +449,75 @@ private void assembleExecutableJar(Path executableFilePath, writeManifest(manifest, outStream); // Sort jar libraries list to avoid inconsistent jar reporting - List sortedJarLibraries = jarLibraries.stream() - .sorted(Comparator.comparing(jarLibrary -> jarLibrary.path().getFileName())).toList(); + sortAndCopyJars(jarLibraries, outStream, copiedEntries, serviceEntries); - // Copy all the jars - for (JarLibrary library : sortedJarLibraries) { - copyJar(outStream, library, copiedEntries, serviceEntries); - } + // Copy merged spi services. + copyMergedSpiServices(serviceEntries, outStream); + } + } + + private void assembleTestExecutableJar(Path executableFilePath, + Manifest manifest, + Collection jarLibraries, + Path testSuiteJsonPath, String jsonCopyPath, + List excludedClasses, String classPathTextCopyPath) + throws IOException { + // Used to prevent adding duplicated entries during the final jar creation. + HashMap copiedEntries = new HashMap<>(); + + // Used to process SPI related metadata entries separately. The reason is unlike the other entry types, + // service loader related information should be merged together in the final executable jar creation. + HashMap serviceEntries = new HashMap<>(); + + try (ZipArchiveOutputStream outStream = new ZipArchiveOutputStream( + new BufferedOutputStream(new FileOutputStream(executableFilePath.toString())))) { + writeManifest(manifest, outStream); + + // Sort jar libraries list to avoid inconsistent jar reporting + sortAndCopyJars(jarLibraries, outStream, copiedEntries, serviceEntries); // Copy merged spi services. - for (Map.Entry entry : serviceEntries.entrySet()) { - String s = entry.getKey(); - StringBuilder service = entry.getValue(); - JarArchiveEntry e = new JarArchiveEntry(s); - outStream.putArchiveEntry(e); - outStream.write(service.toString().getBytes(StandardCharsets.UTF_8)); - outStream.closeArchiveEntry(); + copyMergedSpiServices(serviceEntries, outStream); + + // Write the test suite json file + JarArchiveEntry testSuiteJsonEntry = new JarArchiveEntry(jsonCopyPath); + outStream.putArchiveEntry(testSuiteJsonEntry); + outStream.write(Files.readAllBytes(testSuiteJsonPath)); + outStream.closeArchiveEntry(); + + // Get the module jar paths and copy them to the executable jar + JarArchiveEntry classPathTextEntry = new JarArchiveEntry(classPathTextCopyPath); + outStream.putArchiveEntry(classPathTextEntry); + for (String path : excludedClasses) { + outStream.write((path + "\n").getBytes(StandardCharsets.UTF_8)); } + outStream.closeArchiveEntry(); + } + } + + private static void copyMergedSpiServices(HashMap serviceEntries, + ZipArchiveOutputStream outStream) throws IOException { + for (Map.Entry entry : serviceEntries.entrySet()) { + String s = entry.getKey(); + StringBuilder service = entry.getValue(); + JarArchiveEntry e = new JarArchiveEntry(s); + outStream.putArchiveEntry(e); + outStream.write(service.toString().getBytes(StandardCharsets.UTF_8)); + outStream.closeArchiveEntry(); + } + } + + private void sortAndCopyJars(Collection jarLibraries, ZipArchiveOutputStream outStream, + HashMap copiedEntries, + HashMap serviceEntries) throws IOException { + + List sortedJarLibraries = jarLibraries.stream() + .sorted(Comparator.comparing(jarLibrary -> jarLibrary.path().getFileName())) + .toList(); + + // Copy all the jars + for (JarLibrary library : sortedJarLibraries) { + copyJar(outStream, library, copiedEntries, serviceEntries); } } @@ -458,6 +549,15 @@ private Manifest createManifest() { return manifest; } + private Manifest createTestManifest() { + String mainClassName = "org.ballerinalang.test.runtime.BTestMain"; + Manifest manifest = new Manifest(); + Attributes mainAttributes = manifest.getMainAttributes(); + mainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0"); + mainAttributes.put(Attributes.Name.MAIN_CLASS, mainClassName); + return manifest; + } + /** * Copies a given jar file into the executable fat jar. * @@ -468,58 +568,63 @@ private Manifest createManifest() { * @throws IOException If jar file copying is failed. */ private void copyJar(ZipArchiveOutputStream outStream, JarLibrary jarLibrary, - HashMap copiedEntries, HashMap services) throws IOException { + HashMap copiedEntries, HashMap services) throws IOException { + if (Thread.currentThread().isInterrupted()) { + return; + } + try (ZipFile zipFile = new ZipFile(jarLibrary.path().toFile())) { + ZipArchiveEntryPredicate predicate = entry -> { + String entryName = entry.getName(); + if (entryName.equals("META-INF/MANIFEST.MF")) { + return false; + } + if (entryName.equals("module-info.class")) { + return false; + } + if (entryName.startsWith("META-INF/services")) { + StringBuilder s = services.get(entryName); + if (s == null) { + s = new StringBuilder(); + services.put(entryName, s); + } + char c = '\n'; - ZipFile zipFile = new ZipFile(jarLibrary.path().toFile()); - ZipArchiveEntryPredicate predicate = entry -> { - String entryName = entry.getName(); - if (entryName.equals("META-INF/MANIFEST.MF")) { - return false; - } + int len; + try (BufferedInputStream inStream = new BufferedInputStream(zipFile.getInputStream(entry))) { + while ((len = inStream.read()) != -1) { + c = (char) len; + s.append(c); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + if (c != '\n') { + s.append('\n'); + } - if (entryName.startsWith("META-INF/services")) { - StringBuilder s = services.get(entryName); - if (s == null) { - s = new StringBuilder(); - services.put(entryName, s); + // Its not required to copy SPI entries in here as we'll be adding merged SPI related entries + // separately. Therefore the predicate should be set as false. + return false; } - char c = '\n'; - int len; - try (BufferedInputStream inStream = new BufferedInputStream(zipFile.getInputStream(entry))) { - while ((len = inStream.read()) != -1) { - c = (char) len; - s.append(c); - } - } catch (IOException e) { - throw new RuntimeException(e); + // Skip already copied files or excluded extensions. + if (isCopiedEntry(entryName, copiedEntries)) { + addConflictedJars(jarLibrary, copiedEntries, entryName); + return false; } - if (c != '\n') { - s.append('\n'); + if (isExcludedEntry(entryName)) { + return false; } + // SPIs will be merged first and then put into jar separately. + copiedEntries.put(entryName, jarLibrary); + return true; + }; - // Its not required to copy SPI entries in here as we'll be adding merged SPI related entries - // separately. Therefore the predicate should be set as false. - return false; - } - - // Skip already copied files or excluded extensions. - if (isCopiedEntry(entryName, copiedEntries)) { - addConflictedJars(jarLibrary, copiedEntries, entryName); - return false; - } - if (isExcludedEntry(entryName)) { - return false; - } - // SPIs will be merged first and then put into jar separately. - copiedEntries.put(entryName, jarLibrary); - return true; - }; - - // Transfers selected entries from this zip file to the output stream, while preserving its compression and - // all the other original attributes. - zipFile.copyRawEntries(outStream, predicate); - zipFile.close(); + // Transfers selected entries from this zip file to the output stream, while preserving its compression and + // all the other original attributes. + zipFile.copyRawEntries(outStream, predicate); + } } private static boolean isCopiedEntry(String entryName, HashMap copiedEntries) { @@ -559,6 +664,20 @@ private Path emitExecutable(Path executableFilePath, List emitResult return executableFilePath; } + private Path emitTestExecutable(Path executableFilePath, HashSet jarDependencies, + Path testSuiteJsonPath, String jsonCopyPath, List excludedClasses, + String classPathTextCopyPath) { + Manifest manifest = createTestManifest(); + try { + assembleTestExecutableJar(executableFilePath, manifest, jarDependencies, testSuiteJsonPath, jsonCopyPath, + excludedClasses, classPathTextCopyPath); + } catch (IOException e) { + throw new ProjectException("error while creating the test executable jar file for package '" + + this.packageContext.packageName().toString() + "' : " + e.getMessage(), e); + } + return executableFilePath; + } + private Path emitGraalExecutable(Path executableFilePath, List emitResultDiagnostics) { // Run create executable emitExecutable(executableFilePath, emitResultDiagnostics); @@ -576,7 +695,7 @@ private Path emitGraalExecutable(Path executableFilePath, List emitR nativeImageCommand += File.separator + BIN_DIR_NAME + File.separator + (OS.contains("win") ? "native-image.cmd" : "native-image"); - File commandExecutable = Paths.get(nativeImageCommand).toFile(); + File commandExecutable = Path.of(nativeImageCommand).toFile(); if (!commandExecutable.exists()) { throw new ProjectException("cannot find '" + commandExecutable.getName() + "' in the GRAALVM_HOME/bin " + "directory. Install it using: gu install native-image"); @@ -643,32 +762,6 @@ private Path emitGraalExecutable(Path executableFilePath, List emitR return Path.of(FilenameUtils.removeExtension(executableFilePath.toString())); } - private Map getResources(ModuleContext moduleContext) { - Map resourceMap = new HashMap<>(); - for (DocumentId documentId : moduleContext.resourceIds()) { - String resourceName = ProjectConstants.RESOURCE_DIR_NAME + "/" - + moduleContext.descriptor().org().toString() + "/" - + moduleContext.moduleName().toString() + "/" - + moduleContext.descriptor().version().value().major() + "/" - + moduleContext.resourceContext(documentId).name(); - resourceMap.put(resourceName, moduleContext.resourceContext(documentId).content()); - } - return resourceMap; - } - - private Map getAllResources(ModuleContext moduleContext) { - Map resourceMap = getResources(moduleContext); - for (DocumentId documentId : moduleContext.testResourceIds()) { - String resourceName = ProjectConstants.RESOURCE_DIR_NAME + "/" - + moduleContext.descriptor().org() + "/" - + moduleContext.moduleName().toString() + "/" - + moduleContext.descriptor().version().value().major() + "/" - + moduleContext.resourceContext(documentId).name(); - resourceMap.put(resourceName, moduleContext.resourceContext(documentId).content()); - } - return resourceMap; - } - private PlatformLibraryScope getPlatformLibraryScope(Map dependency) { PlatformLibraryScope scope; String scopeValue = (String) dependency.get(JarLibrary.KEY_SCOPE); @@ -741,10 +834,11 @@ private String getPlatformLibPathFromProvided(String platform, String groupId, S public enum OutputType { EXEC("exec"), BALA("bala"), - GRAAL_EXEC("graal_exec") + GRAAL_EXEC("graal_exec"), + TEST("test") ; - private String value; + private final String value; OutputType(String value) { this.value = value; @@ -842,4 +936,145 @@ private void addProvidedDependencyWarning(List emitResultDiagnostics this.packageContext().descriptor().name().toString())); } } + + private PlatformLibrary codeGeneratedResourcesLibrary(PackageId packageId, PlatformLibraryScope scope) { + Package pkg = packageCache.getPackageOrThrow(packageId); + CompilationCache compilationCache = pkg.project().projectEnvironmentContext().getService( + CompilationCache.class); + return compilationCache.getPlatformSpecificLibrary(this, RESOURCE_DIR_NAME) + .map(path -> new JarLibrary(path, scope)) + .orElse(null); + } + + private Map getPackageResources(PackageContext packageContext) { + Map resourceMap = new HashMap<>(); + for (DocumentId documentId : packageContext.resourceIds()) { + String resourceName = RESOURCE_DIR_NAME + "/" + + packageContext.resourceContext(documentId).name(); + resourceMap.put(resourceName, packageContext.resourceContext(documentId).content()); + } + return resourceMap; + } + + private Map getPackageAndTestResources(PackageContext packageContext) { + Map resourceMap = getPackageResources(packageContext); + for (DocumentId documentId : packageContext.testResourceIds()) { + String resourceName = RESOURCE_DIR_NAME + "/" + + packageContext.resourceContext(documentId).name(); + if (resourceMap.containsKey(resourceName)) { + addConflictingTestResourceDiag(packageContext.descriptor().toString(), resourceName); + } + resourceMap.put(resourceName, packageContext.resourceContext(documentId).content()); + } + return resourceMap; + } + + private void cacheResources(CompilationCache compilationCache, boolean skipTests) { + Map resources = new HashMap<>(); + Map resourceToPkgMap = new HashMap<>(); + List conflictingResourceFiles = new ArrayList<>(); + + // Add resources from dependencies in order + pkgResolution.allDependencies() + .stream() + .filter(pkgDep -> pkgDep.scope() != PackageDependencyScope.TEST_ONLY) + .filter(pkgDep -> !pkgDep.packageInstance().descriptor().isLangLibPackage()) + .map(pkgDep -> pkgDep.packageInstance().packageContext()) + .forEach(pkgContext -> { + Map depResources = getPackageResources(pkgContext); + for (Map.Entry entry : depResources.entrySet()) { + if (resources.containsKey(entry.getKey())) { + addConflictingDepResourceDiag(pkgContext.descriptor().toString(), + resourceToPkgMap.get(entry.getKey()), entry.getKey()); + } + resources.put(entry.getKey(), entry.getValue()); + resourceToPkgMap.put(entry.getKey(), pkgContext.descriptor().toString()); + } + }); + // Add resources from the package + Map packageResources = skipTests ? getPackageResources(packageContext) : + getPackageAndTestResources(packageContext); + for (Map.Entry entry : packageResources.entrySet()) { + if (resources.containsKey(entry.getKey())) { + addConflictingDepResourceDiag(packageContext.descriptor().toString(), + resourceToPkgMap.get(entry.getKey()), entry.getKey()); + } + resources.put(entry.getKey(), entry.getValue()); + resourceToPkgMap.put(entry.getKey(), packageContext.descriptor().toString()); + } + + // Add generated resources and check for conflicts for build projects + if (!this.packageContext().project().kind().equals(ProjectKind.BALA_PROJECT)) { + Map generatedResources = ProjectUtils.getAllGeneratedResources( + packageContext.project().generatedResourcesDir()); + for (Map.Entry entry : generatedResources.entrySet()) { + if (resources.containsKey(entry.getKey())) { + if (packageResources.containsKey(entry.getKey())) { + conflictingResourceFiles.add(entry.getKey()); + continue; + } + // Issue a warning for conflicts with dependency resources + addConflictingGenResourceDiag(resourceToPkgMap.get(entry.getKey()), + packageContext.descriptor().toString(), entry.getKey()); + } + resources.put(entry.getKey(), entry.getValue()); + } + // Handle conflicting resources + if (!conflictingResourceFiles.isEmpty()) { + throw new ProjectException(getConflictingResourcesMsg(packageContext.descriptor().toString(), + conflictingResourceFiles)); + } + } + + // Cache the resources if there are any + if (!resources.isEmpty()) { + try { + String resourceJarName = RESOURCE_DIR_NAME + JAR_FILE_NAME_SUFFIX; + CompiledJarFile resourceJar = new CompiledJarFile(""); + resourceJar.jarEntries.putResourceEntries(resources); + try (ByteArrayOutputStream byteStream = resourceJar.toByteArrayStream()) { + compilationCache.cachePlatformSpecificLibrary(this, resourceJarName, byteStream); + } + } catch (IOException e) { + throw new ProjectException("Failed to cache resources jar, package: " + + packageContext.packageName(), e); + } + } + } + + private void addConflictingDepResourceDiag(String packageDesc, String existingPackageDesc, String resourceName) { + DiagnosticInfo diagnosticInfo = new DiagnosticInfo( + ProjectDiagnosticErrorCode.CONFLICTING_RESOURCE_FILE.diagnosticId(), + String.format("detected conflicting resource files. The packages '" + + existingPackageDesc + "' and '" + packageDesc + + "' both export a resource with the same name '" + resourceName + + "'. Picking the resource exported by '" + packageDesc + "'."), + DiagnosticSeverity.WARNING); + conflictedResourcesDiagnostics.add(new PackageDiagnostic(diagnosticInfo, + this.packageContext.descriptor().name().toString())); + } + + private void addConflictingGenResourceDiag(String existingPackageDesc, String packageDesc, String resourceName) { + DiagnosticInfo diagnosticInfo = new DiagnosticInfo( + ProjectDiagnosticErrorCode.CONFLICTING_RESOURCE_FILE.diagnosticId(), + String.format("detected conflicting resource files. The package " + existingPackageDesc + + " and the generated resources for the current package '" + packageDesc + + "' both export a resource with the same name '" + resourceName + "'. " + + "Picking the generated resource file."), + DiagnosticSeverity.WARNING); + conflictedResourcesDiagnostics.add(new PackageDiagnostic( + diagnosticInfo, this.packageContext.descriptor().name().toString())); + } + + private void addConflictingTestResourceDiag(String packageDesc, String resourceName) { + DiagnosticInfo diagnosticInfo = new DiagnosticInfo( + ProjectDiagnosticErrorCode.CONFLICTING_RESOURCE_FILE.diagnosticId(), + String.format("detected conflicting resource files. The test specific resources and package " + + "resources for '" + packageDesc + "' both export a resource with the same name '" + + resourceName + "'. Picking the test specific resource."), + DiagnosticSeverity.WARNING); + conflictedResourcesDiagnostics.add(new PackageDiagnostic(diagnosticInfo, + this.packageContext.descriptor().name().toString())); + } + } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/JBallerinaBalaWriter.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/JBallerinaBalaWriter.java index 7c49f2660322..fac6f51d05c2 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/JBallerinaBalaWriter.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/JBallerinaBalaWriter.java @@ -35,7 +35,6 @@ import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -58,7 +57,7 @@ public class JBallerinaBalaWriter extends BalaWriter { public static final String LIBS = "libs"; public static final String COMPILER_PLUGIN = "compiler-plugin"; public static final String ANNON = "annon"; - private JBallerinaBackend backend; + private final JBallerinaBackend backend; public JBallerinaBalaWriter(JBallerinaBackend backend) { this.backend = backend; @@ -97,7 +96,7 @@ protected Optional addPlatformLibs(ZipOutputStream balaOutputStream) // null check is added for spot bug with the toml validation filename cannot be null String fileName = Optional.ofNullable(libPath.getFileName()) .map(Path::toString).orElse(ANNON); - Path entryPath = Paths.get(PLATFORM) + Path entryPath = Path.of(PLATFORM) .resolve(target) .resolve(fileName); // create a zip entry for each file @@ -138,32 +137,28 @@ protected void addCompilerPlugin(ZipOutputStream balaOutputStream) throws IOExce List compilerPluginLibPaths = new ArrayList<>(); List compilerPluginDependencies = this.compilerPluginToml.get().getCompilerPluginDependencies(); - if (compilerPluginDependencies.get(0) == null) { + if (compilerPluginDependencies.isEmpty()) { throw new ProjectException("No dependencies found in CompilerPlugin.toml file"); } - if (!compilerPluginDependencies.isEmpty()) { - - // Iterate through compiler plugin dependencies and add them to bala - // organization would be - // -- Bala Root - // - compiler-plugin/ - // - libs - // - java-library1.jar - // - java-library2.jar - - - // Iterate jars and create directories for each target - for (String compilerPluginLib : compilerPluginDependencies) { - Path libPath = this.packageContext.project().sourceRoot().resolve(compilerPluginLib); - // null check is added for spot bug with the toml validation filename cannot be null - String fileName = Optional.ofNullable(libPath.getFileName()) - .map(Path::toString).orElse(ANNON); - Path entryPath = Paths.get("compiler-plugin").resolve("libs").resolve(fileName); - // create a zip entry for each file - putZipEntry(balaOutputStream, entryPath, new FileInputStream(libPath.toString())); - compilerPluginLibPaths.add(entryPath.toString()); - } + // Iterate through compiler plugin dependencies and add them to bala + // organization would be + // -- Bala Root + // - compiler-plugin/ + // - libs + // - java-library1.jar + // - java-library2.jar + + // Iterate jars and create directories for each target + for (String compilerPluginLib : compilerPluginDependencies) { + Path libPath = this.packageContext.project().sourceRoot().resolve(compilerPluginLib); + // null check is added for spot bug with the toml validation filename cannot be null + String fileName = Optional.ofNullable(libPath.getFileName()) + .map(Path::toString).orElse(ANNON); + Path entryPath = Path.of("compiler-plugin").resolve("libs").resolve(fileName); + // create a zip entry for each file + putZipEntry(balaOutputStream, entryPath, new FileInputStream(libPath.toString())); + compilerPluginLibPaths.add(entryPath.toString()); } CompilerPluginJson compilerPluginJson = new CompilerPluginJson( @@ -176,7 +171,7 @@ protected void addCompilerPlugin(ZipOutputStream balaOutputStream) throws IOExce .registerTypeHierarchyAdapter(String.class, new JsonStringsAdaptor()).setPrettyPrinting().create(); try { - putZipEntry(balaOutputStream, Paths.get(COMPILER_PLUGIN, COMPILER_PLUGIN_JSON), + putZipEntry(balaOutputStream, Path.of(COMPILER_PLUGIN, COMPILER_PLUGIN_JSON), new ByteArrayInputStream( gson.toJson(compilerPluginJson).getBytes(Charset.defaultCharset()))); } catch (IOException e) { @@ -209,7 +204,7 @@ protected void addBalTool(ZipOutputStream balaOutputStream) throws IOException { // null check is added for spot bug with the toml validation filename cannot be null String fileName = Optional.ofNullable(libPath.getFileName()) .map(Path::toString).orElse(ANNON); - Path entryPath = Paths.get(TOOL).resolve(LIBS).resolve(fileName); + Path entryPath = Path.of(TOOL).resolve(LIBS).resolve(fileName); // create a zip entry for each file putZipEntry(balaOutputStream, entryPath, new FileInputStream(libPath.toString())); balToolLibPaths.add(entryPath.toString()); @@ -222,7 +217,7 @@ protected void addBalTool(ZipOutputStream balaOutputStream) throws IOException { .registerTypeHierarchyAdapter(String.class, new JsonStringsAdaptor()).setPrettyPrinting().create(); try { - putZipEntry(balaOutputStream, Paths.get(TOOL, BAL_TOOL_JSON), + putZipEntry(balaOutputStream, Path.of(TOOL, BAL_TOOL_JSON), new ByteArrayInputStream( gson.toJson(balToolJson).getBytes(Charset.defaultCharset()))); } catch (IOException e) { @@ -277,7 +272,7 @@ private boolean hasPlatformDependencies(Map pl } private Optional readCompilerPluginToml() { - Optional compilerPluginToml = backend.packageContext().project() + Optional compilerPluginToml = backend.packageContext().project() .currentPackage().compilerPluginToml(); if (compilerPluginToml.isPresent()) { diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/JarResolver.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/JarResolver.java index b037d540fcc3..456653b6b70f 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/JarResolver.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/JarResolver.java @@ -37,6 +37,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import static io.ballerina.identifier.Utils.encodeNonFunctionIdentifier; @@ -58,7 +59,7 @@ public class JarResolver { private final PackageContext rootPackageContext; private final List diagnosticList; private DiagnosticResult diagnosticResult; - private List providedPlatformLibs; + private final List providedPlatformLibs; private ClassLoader classLoaderWithAllJars; @@ -110,10 +111,16 @@ public Collection getJarFilePathsRequiredForExecution() { }); // 3) Add the runtime library path + String packageName = getPackageName(rootPackageContext); jarFiles.add(new JarLibrary(jBalBackend.runtimeLibrary().path(), PlatformLibraryScope.DEFAULT, - getPackageName(rootPackageContext))); + packageName)); + // Add resources + Optional.ofNullable(jBalBackend.codeGeneratedResourcesLibrary(rootPackageContext.packageId())) + .ifPresent(library -> jarFiles.add( + new JarLibrary(library.path(), PlatformLibraryScope.DEFAULT, + packageName))); // TODO Filter out duplicate jar entries return jarFiles; } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/JvmTarget.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/JvmTarget.java index fa5e1690fc4b..f252659873fe 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/JvmTarget.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/JvmTarget.java @@ -33,6 +33,7 @@ public enum JvmTarget implements CompilerBackend.TargetPlatform { this.code = code; } + @Override public String code() { return code; } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/MdDocumentContext.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/MdDocumentContext.java index 75584f86ab5f..a5f807086fee 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/MdDocumentContext.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/MdDocumentContext.java @@ -29,9 +29,9 @@ */ class MdDocumentContext { private TextDocument textDocument; - private DocumentId documentId; - private String name; - private String content; + private final DocumentId documentId; + private final String name; + private final String content; private MdDocumentContext(DocumentId documentId, String name, String content) { this.documentId = documentId; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Module.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Module.java index 0370a09f54de..f686084bef85 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Module.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Module.java @@ -19,7 +19,6 @@ import java.util.Collection; import java.util.Comparator; -import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; @@ -42,10 +41,7 @@ public class Module { private final Package packageInstance; private final Map srcDocs; private final Map testSrcDocs; - private final Map resources; - private final Map testResources; private final Function populateDocumentFunc; - private final Function populateResourceFunc; private Optional moduleMd = null; @@ -55,12 +51,8 @@ public class Module { this.srcDocs = new ConcurrentHashMap<>(); this.testSrcDocs = new ConcurrentHashMap<>(); - this.resources = new ConcurrentHashMap<>(); - this.testResources = new ConcurrentHashMap<>(); this.populateDocumentFunc = documentId -> new Document( this.moduleContext.documentContext(documentId), this); - this.populateResourceFunc = documentId -> new Resource( - this.moduleContext.resourceContext(documentId), this); } static Module from(ModuleContext moduleContext, Package packageInstance) { @@ -91,12 +83,14 @@ public Collection testDocumentIds() { return this.moduleContext.testSrcDocumentIds(); } + @Deprecated(since = "2201.10.0", forRemoval = true) public Collection resourceIds() { - return this.moduleContext.resourceIds(); + return this.moduleContext.project().currentPackage().resourceIds(); } + @Deprecated(since = "2201.10.0", forRemoval = true) public Collection testResourceIds() { - return this.moduleContext.testResourceIds(); + return this.moduleContext.project().currentPackage().getDefaultModule().testResourceIds(); } public Document document(DocumentId documentId) { @@ -108,13 +102,10 @@ public Document document(DocumentId documentId) { } } + @Deprecated(since = "2201.10.0", forRemoval = true) public Resource resource(DocumentId documentId) { + return this.packageInstance.resource(documentId); // TODO Should we throw an error if the documentId is not present - if (resourceIds().contains(documentId)) { - return this.resources.computeIfAbsent(documentId, this.populateResourceFunc); - } else { - return this.testResources.computeIfAbsent(documentId, this.populateResourceFunc); - } } @@ -155,7 +146,7 @@ public Optional moduleMd() { return this.moduleMd; } - private static class DocumentIterable implements Iterable { + private static class DocumentIterable implements Iterable { private final Collection documentList; public DocumentIterable(Collection documentList) { @@ -168,7 +159,7 @@ public Iterator iterator() { } @Override - public Spliterator spliterator() { + public Spliterator spliterator() { return this.documentList.spliterator(); } } @@ -177,30 +168,26 @@ public Spliterator spliterator() { * Inner class that handles module modifications. */ public static class Modifier { - private ModuleId moduleId; - private ModuleDescriptor moduleDescriptor; + private final ModuleId moduleId; + private final ModuleDescriptor moduleDescriptor; private Map srcDocContextMap; private Map testDocContextMap; - private boolean isDefaultModule; + private final boolean isDefaultModule; private final List dependencies; - private Package packageInstance; - private Project project; + private final Package packageInstance; + private final Project project; private MdDocumentContext moduleMdContext; - private final Map resourceContextMap; - private final Map testResourceContextMap; private Modifier(Module oldModule) { moduleId = oldModule.moduleId(); moduleDescriptor = oldModule.descriptor(); srcDocContextMap = copySrcDocs(oldModule, oldModule.moduleContext.srcDocumentIds()); - testDocContextMap = copySrcDocs(oldModule, oldModule.moduleContext.testSrcDocumentIds());; + testDocContextMap = copySrcDocs(oldModule, oldModule.moduleContext.testSrcDocumentIds()); isDefaultModule = oldModule.isDefaultModule(); dependencies = oldModule.moduleContext().moduleDescDependencies(); packageInstance = oldModule.packageInstance; project = oldModule.project(); moduleMdContext = oldModule.moduleContext.moduleMdContext().orElse(null); - resourceContextMap = copyResources(oldModule, oldModule.moduleContext.resourceIds()); - testResourceContextMap = copyResources(oldModule, oldModule.moduleContext.testResourceIds()); } Modifier updateDocument(DocumentContext newDocContext) { @@ -218,9 +205,8 @@ Modifier updateDocument(DocumentContext newDocContext) { * @param resourceConfig configurations to create the resource * @return an instance of the Module.Modifier */ + @Deprecated(since = "2201.10.0", forRemoval = true) public Modifier addResource(ResourceConfig resourceConfig) { - ResourceContext newResourceContext = ResourceContext.from(resourceConfig); - this.resourceContextMap.put(newResourceContext.documentId(), newResourceContext); return this; } @@ -230,9 +216,8 @@ public Modifier addResource(ResourceConfig resourceConfig) { * @param resourceConfig configurations to create the test resource * @return an instance of the Module.Modifier */ + @Deprecated(since = "2201.10.0", forRemoval = true) public Modifier addTestResource(ResourceConfig resourceConfig) { - ResourceContext newResourceContext = ResourceContext.from(resourceConfig); - this.testResourceContextMap.put(newResourceContext.documentId(), newResourceContext); return this; } @@ -242,13 +227,8 @@ public Modifier addTestResource(ResourceConfig resourceConfig) { * @param documentId documentId of the resource to remove * @return an instance of the Module.Modifier */ + @Deprecated(since = "2201.10.0", forRemoval = true) public Modifier removeResource(DocumentId documentId) { - - if (this.resourceContextMap.containsKey(documentId)) { - this.resourceContextMap.remove(documentId); - } else { - this.testResourceContextMap.remove(documentId); - } return this; } @@ -313,15 +293,6 @@ public Module apply() { return createNewModule(this.srcDocContextMap, this.testDocContextMap); } - private Map copyResources(Module oldModule, Collection documentIds) { - Map resourceContextMap = new HashMap<>(); - for (DocumentId documentId : documentIds) { - resourceContextMap.put(documentId, oldModule.moduleContext.resourceContext(documentId)); - } - return resourceContextMap; - } - - private Map copySrcDocs(Module oldModule, Collection documentIds) { Map srcDocContextMap = new LinkedHashMap<>(); for (DocumentId documentId : documentIds) { @@ -335,8 +306,7 @@ private Module createNewModule(Map srcDocContextMap Set moduleContextSet = new HashSet<>(); ModuleContext newModuleContext = new ModuleContext(this.project, this.moduleId, this.moduleDescriptor, this.isDefaultModule, srcDocContextMap, - testDocContextMap, this.moduleMdContext, this.dependencies, this.resourceContextMap, - this.testResourceContextMap); + testDocContextMap, this.moduleMdContext, this.dependencies); moduleContextSet.add(newModuleContext); // add dependant modules including transitives @@ -348,8 +318,7 @@ private Module createNewModule(Map srcDocContextMap Modifier module = this.packageInstance.module(dependentDescriptor.name()).modify(); moduleContextSet.add(new ModuleContext(this.project, module.moduleId, dependentDescriptor, module.isDefaultModule, module.srcDocContextMap, - module.testDocContextMap, module.moduleMdContext, module.dependencies, - module.resourceContextMap, module.testResourceContextMap)); + module.testDocContextMap, module.moduleMdContext, module.dependencies)); } Package newPackage = this.packageInstance.modify().updateModules(moduleContextSet).apply(); @@ -377,7 +346,7 @@ private Collection getAllDependants( visited.add(updatedModuleDescriptor); Collection directDependents = this.project.currentPackage() .moduleDependencyGraph().getDirectDependents(updatedModuleDescriptor); - if (directDependents.size() > 0) { + if (!directDependents.isEmpty()) { dependants.addAll(directDependents); for (ModuleDescriptor directDependent : directDependents) { getAllDependants(directDependent, visited, dependants); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ModuleConfig.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ModuleConfig.java index a4b12d111bbe..2898d66560f2 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ModuleConfig.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ModuleConfig.java @@ -17,7 +17,6 @@ */ package io.ballerina.projects; -import java.util.Collections; import java.util.List; import java.util.Optional; @@ -34,25 +33,19 @@ public class ModuleConfig { private final List testSrcDocs; private final List dependencies; private final DocumentConfig moduleMd; - private final List resources; - private final List testResources; private ModuleConfig(ModuleId moduleId, ModuleDescriptor moduleDescriptor, List srcDocs, List testSrcDocs, DocumentConfig moduleMd, - List dependencies, - List resources, - List testResources) { + List dependencies) { this.moduleId = moduleId; this.moduleDescriptor = moduleDescriptor; this.srcDocs = srcDocs; this.testSrcDocs = testSrcDocs; this.dependencies = dependencies; this.moduleMd = moduleMd; - this.resources = resources; - this.testResources = testResources; } public static ModuleConfig from(ModuleId moduleId, @@ -61,8 +54,7 @@ public static ModuleConfig from(ModuleId moduleId, List testSrcDocs, DocumentConfig moduleMd, List dependencies) { - return new ModuleConfig(moduleId, moduleDescriptor, srcDocs, testSrcDocs, moduleMd, dependencies, - Collections.emptyList(), Collections.emptyList()); + return new ModuleConfig(moduleId, moduleDescriptor, srcDocs, testSrcDocs, moduleMd, dependencies); } public static ModuleConfig from(ModuleId moduleId, @@ -74,7 +66,7 @@ public static ModuleConfig from(ModuleId moduleId, List resources, List testResources) { return new ModuleConfig( - moduleId, moduleDescriptor, srcDocs, testSrcDocs, moduleMd, dependencies, resources, testResources); + moduleId, moduleDescriptor, srcDocs, testSrcDocs, moduleMd, dependencies); } public ModuleId moduleId() { @@ -105,11 +97,13 @@ public Optional moduleMd() { return Optional.ofNullable(this.moduleMd); } + @Deprecated(since = "2201.10.0", forRemoval = true) public List resources() { - return resources; + return null; } + @Deprecated(since = "2201.10.0", forRemoval = true) public List testResources() { - return testResources; + return null; } } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ModuleContext.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ModuleContext.java index 4c5f3159c77f..73b0754c448d 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ModuleContext.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ModuleContext.java @@ -31,6 +31,7 @@ import org.ballerinalang.model.elements.Flag; import org.ballerinalang.model.elements.PackageID; import org.wso2.ballerinalang.compiler.BIRPackageSymbolEnter; +import org.wso2.ballerinalang.compiler.PackageCache; import org.wso2.ballerinalang.compiler.bir.writer.BIRBinaryWriter; import org.wso2.ballerinalang.compiler.diagnostic.BLangDiagnosticLocation; import org.wso2.ballerinalang.compiler.semantics.analyzer.SymbolEnter; @@ -44,9 +45,10 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -54,6 +56,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.function.Supplier; import static org.ballerinalang.model.tree.SourceKind.REGULAR_SOURCE; import static org.ballerinalang.model.tree.SourceKind.TEST_SOURCE; @@ -74,10 +77,6 @@ class ModuleContext { private final Collection testSrcDocIds; private final MdDocumentContext moduleMdContext; private final Map testDocContextMap; - private final Collection resourceIds; - private final Collection testResourceIds; - private final Map resourceContextMap; - private final Map testResourceContextMap; private final Project project; private final CompilationCache compilationCache; private final List moduleDescDependencies; @@ -98,9 +97,7 @@ class ModuleContext { Map srcDocContextMap, Map testDocContextMap, MdDocumentContext moduleMd, - List moduleDescDependencies, - Map resourceContextMap, - Map testResourceContextMap) { + List moduleDescDependencies) { this.project = project; this.moduleId = moduleId; this.moduleDescriptor = moduleDescriptor; @@ -111,10 +108,7 @@ class ModuleContext { this.testSrcDocIds = Collections.unmodifiableCollection(testDocContextMap.keySet()); this.moduleMdContext = moduleMd; this.moduleDescDependencies = Collections.unmodifiableList(moduleDescDependencies); - this.resourceContextMap = resourceContextMap; - this.testResourceContextMap = testResourceContextMap; - this.resourceIds = Collections.unmodifiableCollection(resourceContextMap.keySet()); - this.testResourceIds = Collections.unmodifiableCollection(testResourceContextMap.keySet()); + ProjectEnvironment projectEnvironment = project.projectEnvironmentContext(); this.bootstrap = new Bootstrap(projectEnvironment.getService(PackageResolver.class)); @@ -134,20 +128,10 @@ static ModuleContext from(Project project, ModuleConfig moduleConfig, boolean di disableSyntaxTree)); } - Map resourceContextMap = new HashMap<>(); - for (ResourceConfig resourceConfig : moduleConfig.resources()) { - resourceContextMap.put(resourceConfig.documentId(), ResourceContext.from(resourceConfig)); - } - - Map testResourceContextMap = new HashMap<>(); - for (ResourceConfig resourceConfig : moduleConfig.testResources()) { - testResourceContextMap.put(resourceConfig.documentId(), ResourceContext.from(resourceConfig)); - } - return new ModuleContext(project, moduleConfig.moduleId(), moduleConfig.moduleDescriptor(), moduleConfig.isDefaultModule(), srcDocContextMap, testDocContextMap, moduleConfig.moduleMd().map(c ->MdDocumentContext.from(c)).orElse(null), - moduleConfig.dependencies(), resourceContextMap, testResourceContextMap); + moduleConfig.dependencies()); } ModuleId moduleId() { @@ -170,14 +154,6 @@ Collection testSrcDocumentIds() { return this.testSrcDocIds; } - Collection resourceIds() { - return this.resourceIds; - } - - Collection testResourceIds() { - return this.testResourceIds; - } - DocumentContext documentContext(DocumentId documentId) { if (this.srcDocIds.contains(documentId)) { return this.srcDocContextMap.get(documentId); @@ -186,14 +162,6 @@ DocumentContext documentContext(DocumentId documentId) { } } - ResourceContext resourceContext(DocumentId documentId) { - if (this.resourceIds.contains(documentId)) { - return this.resourceContextMap.get(documentId); - } else { - return this.testResourceContextMap.get(documentId); - } - } - Project project() { return this.project; } @@ -403,8 +371,7 @@ static void compileInternal(ModuleContext moduleContext, CompilerContext compile moduleContext.bootstrap.loadLangLib(compilerContext, moduleCompilationId); } - org.wso2.ballerinalang.compiler.PackageCache packageCache = - org.wso2.ballerinalang.compiler.PackageCache.getInstance(compilerContext); + PackageCache packageCache = PackageCache.getInstance(compilerContext); SymbolEnter symbolEnter = SymbolEnter.getInstance(compilerContext); CompilerPhaseRunner compilerPhaseRunner = CompilerPhaseRunner.getInstance(compilerContext); @@ -434,8 +401,12 @@ static void compileInternal(ModuleContext moduleContext, CompilerContext compile packageCache.putSymbol(pkgNode.packageID, pkgNode.symbol); compilerPhaseRunner.performTypeCheckPhases(pkgNode); } catch (Throwable t) { - assert false : "Compilation failed due to" + - (t.getMessage() != null ? ": " + t.getMessage() : " an unhandled exception"); + assert false : "Compilation failed due to " + ((Supplier) () -> { + StringWriter errors = new StringWriter(); + t.printStackTrace(new PrintWriter(errors)); + return errors.toString(); + }).get(); + compilerPhaseRunner.addDiagnosticForUnhandledException(pkgNode, t); } moduleContext.bLangPackage = pkgNode; @@ -453,8 +424,11 @@ static void generateCodeInternal(ModuleContext moduleContext, try { compilerPhaseRunner.performBirGenPhases(moduleContext.bLangPackage); } catch (Throwable t) { - assert false : "Compilation failed due to" + - (t.getMessage() != null ? ": " + t.getMessage() : " an unhandled exception"); + assert false : "Compilation failed due to " + ((Supplier) () -> { + StringWriter errors = new StringWriter(); + t.printStackTrace(new PrintWriter(errors)); + return errors.toString(); + }).get(); compilerPhaseRunner.addDiagnosticForUnhandledException(moduleContext.bLangPackage, t); return; } @@ -541,8 +515,7 @@ static void resolveDependenciesFromBALAInternal(ModuleContext moduleContext) { } static void loadPackageSymbolInternal(ModuleContext moduleContext, CompilerContext compilerContext) { - org.wso2.ballerinalang.compiler.PackageCache packageCache = - org.wso2.ballerinalang.compiler.PackageCache.getInstance(compilerContext); + PackageCache packageCache = PackageCache.getInstance(compilerContext); BIRPackageSymbolEnter birPackageSymbolEnter = BIRPackageSymbolEnter.getInstance(compilerContext); PackageID moduleCompilationId = moduleContext.descriptor().moduleCompilationId(); @@ -578,7 +551,7 @@ ModuleContext duplicate(Project project) { } return new ModuleContext(project, this.moduleId, this.moduleDescriptor, this.isDefaultModule, srcDocContextMap, testDocContextMap, this.moduleMdContext().orElse(null), - this.moduleDescDependencies, this.resourceContextMap, this.testResourceContextMap); + this.moduleDescDependencies); } /** diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ModuleMd.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ModuleMd.java index 00ef059c7e3d..43da5eac1d9b 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ModuleMd.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ModuleMd.java @@ -60,9 +60,9 @@ public Modifier modify() { */ public static class Modifier { private String content; - private String name; - private DocumentId documentId; - private Module oldModule; + private final String name; + private final DocumentId documentId; + private final Module oldModule; private Modifier(ModuleMd oldDocument) { this.content = oldDocument.mdDocumentContext.content(); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/NullBackend.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/NullBackend.java index cbffe9dbd014..f20ab67a0489 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/NullBackend.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/NullBackend.java @@ -77,6 +77,11 @@ public PlatformLibrary codeGeneratedTestLibrary(PackageId packageId, ModuleName return null; } + @Override + public PlatformLibrary codeGeneratedResourcesLibrary(PackageId packageId) { + return null; + } + @Override public PlatformLibrary runtimeLibrary() { return null; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Package.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Package.java index 8865d1950f7c..d6f6b9d6d46b 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Package.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Package.java @@ -5,6 +5,7 @@ import io.ballerina.projects.internal.DependencyManifestBuilder; import io.ballerina.projects.internal.ManifestBuilder; import io.ballerina.projects.internal.model.CompilerPluginDescriptor; +import io.ballerina.projects.util.ProjectUtils; import io.ballerina.tools.diagnostics.Diagnostic; import org.ballerinalang.model.elements.PackageID; import org.wso2.ballerinalang.compiler.PackageCache; @@ -42,6 +43,9 @@ public class Package { private Optional cloudToml = Optional.empty(); private Optional compilerPluginToml = Optional.empty(); private Optional balToolToml = Optional.empty(); + private final Map resources; + private final Map testResources; + private final Function populateResourceFunc; private Package(PackageContext packageContext, Project project) { this.packageContext = packageContext; @@ -49,6 +53,10 @@ private Package(PackageContext packageContext, Project project) { this.moduleMap = new ConcurrentHashMap<>(); this.populateModuleFunc = moduleId -> Module.from( this.packageContext.moduleContext(moduleId), this); + this.resources = new ConcurrentHashMap<>(); + this.testResources = new ConcurrentHashMap<>(); + this.populateResourceFunc = documentId -> new Resource( + this.packageContext.resourceContext(documentId), this); } static Package from(Project project, PackageConfig packageConfig, CompilationOptions compilationOptions) { @@ -227,6 +235,24 @@ public Optional packageMd() { return this.packageMd; } + public Collection resourceIds() { + return this.packageContext.resourceIds(); + } + + public Collection testResourceIds() { + return this.packageContext.testResourceIds(); + } + + public Resource resource(DocumentId documentId) { + // TODO Should we throw an error if the documentId is not present + if (resourceIds().contains(documentId)) { + return this.resources.computeIfAbsent(documentId, this.populateResourceFunc); + } else { + return this.testResources.computeIfAbsent(documentId, this.populateResourceFunc); + } + } + + Package duplicate(Project project) { return new Package(packageContext.duplicate(project), project); } @@ -238,7 +264,7 @@ Package duplicate(Project project) { * in form of a {@code DiagnosticResult} instance. *

* Here is a sample usage of this API:

-     *   Project project = BuildProject.load(Paths.get(...));
+     *   Project project = BuildProject.load(Path.of(...));
      *   Package currentPackage = project.currentPackage();
      *   DiagnosticResult diagnosticsResult = currentPackage.runCodeGenAndModifyPlugins();
      *
@@ -294,7 +320,7 @@ public DiagnosticResult runCodeGenAndModifyPlugins() {
      * reported by the code generator tasks in form of a {@code CodeGeneratorResult} instance.
      * 

* Here is a sample usage of this API:

-     *   Project project = BuildProject.load(Paths.get(...));
+     *   Project project = BuildProject.load(Path.of(...));
      *   Package currentPackage = project.currentPackage();
      *   Package packageWithGenFiles = currentPackage.runCodeGeneratorPlugins();
      *
@@ -336,7 +362,7 @@ public CodeGeneratorResult runCodeGeneratorPlugins() {
      * reported by the code modifier tasks in form of a {@code CodeModifierResult} instance.
      * 

* Here is a sample usage of this API:

-     *   Project project = BuildProject.load(Paths.get(...));
+     *   Project project = BuildProject.load(Path.of(...));
      *   Package currentPackage = project.currentPackage();
      *   Package packageWithGenFiles = currentPackage.runCodeModifierPlugins();
      *
@@ -388,7 +414,7 @@ public PackageResolution getResolution(ResolutionOptions resolutionOptions) {
         return this.packageContext.getResolution(newCompOptions, true);
     }
 
-    private static class ModuleIterable implements Iterable {
+    private static class ModuleIterable implements Iterable {
 
         private final Collection moduleList;
 
@@ -402,7 +428,7 @@ public Iterator iterator() {
         }
 
         @Override
-        public Spliterator spliterator() {
+        public Spliterator spliterator() {
             return this.moduleList.spliterator();
         }
     }
@@ -411,19 +437,21 @@ public Spliterator spliterator() {
      * Inner class that handles package modifications.
      */
     public static class Modifier {
-        private PackageId packageId;
+        private final PackageId packageId;
         private PackageManifest packageManifest;
         private DependencyManifest dependencyManifest;
-        private Map moduleContextMap;
-        private Project project;
+        private final Map moduleContextMap;
+        private final Project project;
         private final DependencyGraph dependencyGraph;
-        private CompilationOptions compilationOptions;
+        private final CompilationOptions compilationOptions;
         private TomlDocumentContext ballerinaTomlContext;
         private TomlDocumentContext dependenciesTomlContext;
         private TomlDocumentContext cloudTomlContext;
         private TomlDocumentContext compilerPluginTomlContext;
         private TomlDocumentContext balToolTomlContext;
         private MdDocumentContext packageMdContext;
+        private final Map resourceContextMap;
+        private final Map testResourceContextMap;
 
         public Modifier(Package oldPackage) {
             this.packageId = oldPackage.packageId();
@@ -439,6 +467,8 @@ public Modifier(Package oldPackage) {
             this.compilerPluginTomlContext = oldPackage.packageContext.compilerPluginTomlContext().orElse(null);
             this.balToolTomlContext = oldPackage.packageContext.balToolTomlContext().orElse(null);
             this.packageMdContext = oldPackage.packageContext.packageMdContext().orElse(null);
+            resourceContextMap = copyResources(oldPackage, oldPackage.packageContext.resourceIds());
+            testResourceContextMap = copyResources(oldPackage, oldPackage.packageContext.testResourceIds());
         }
 
         Modifier updateModules(Set newModuleContexts) {
@@ -571,7 +601,6 @@ public Modifier removePackageMd() {
         }
 
 
-
         Modifier updateBallerinaToml(BallerinaToml ballerinaToml) {
             this.ballerinaTomlContext = ballerinaToml.ballerinaTomlContext();
             updatePackageManifest();
@@ -624,13 +653,20 @@ private Map copyModules(Package oldPackage) {
         }
 
         private Package createNewPackage() {
+            Package oldPackage = this.project.currentPackage();
+            PackageResolution oldResolution = oldPackage.getResolution();
             PackageContext newPackageContext = new PackageContext(this.project, this.packageId, this.packageManifest,
                     this.dependencyManifest, this.ballerinaTomlContext, this.dependenciesTomlContext,
                     this.cloudTomlContext, this.compilerPluginTomlContext, this.balToolTomlContext,
                     this.packageMdContext, this.compilationOptions, this.moduleContextMap,
-                    DependencyGraph.emptyGraph());
+                    DependencyGraph.emptyGraph(), this.resourceContextMap,
+                    this.testResourceContextMap);
             this.project.setCurrentPackage(new Package(newPackageContext, this.project));
-
+            if (isOldDependencyGraphValid(oldPackage, this.project.currentPackage())) {
+                this.project.currentPackage().packageContext().getResolution(oldResolution);
+            } else {
+                this.project.compilerPluginContexts().clear();
+            }
             CompilationOptions offlineCompOptions = CompilationOptions.builder().setOffline(true).build();
             offlineCompOptions = offlineCompOptions.acceptTheirs(project.currentPackage().compilationOptions());
             DependencyGraph newDepGraph = this.project.currentPackage().packageContext()
@@ -639,6 +675,22 @@ private Package createNewPackage() {
             return this.project.currentPackage();
         }
 
+        private static boolean isOldDependencyGraphValid(Package oldPackage, Package currentPackage) {
+            Set oldPackageImports = ProjectUtils.getPackageImports(oldPackage);
+            Set currentPackageImports = ProjectUtils.getPackageImports(currentPackage);
+            String oldDependencyTomlContent = oldPackage.packageContext.dependenciesTomlContext()
+                    .map(d -> d.tomlDocument().textDocument().toString()).orElse("");
+            String currentDependencyTomlContent = currentPackage.packageContext.dependenciesTomlContext()
+                    .map(d -> d.tomlDocument().textDocument().toString()).orElse("");
+            String oldBallerinaTomlContent = oldPackage.packageContext.ballerinaTomlContext()
+                    .map(d -> d.tomlDocument().textDocument().toString()).orElse("");
+            String currentBallerinaTomlContent = currentPackage.packageContext.ballerinaTomlContext()
+                    .map(d -> d.tomlDocument().textDocument().toString()).orElse("");
+            return oldPackageImports.equals(currentPackageImports) &&
+                    oldDependencyTomlContent.equals(currentDependencyTomlContent) &&
+                    oldBallerinaTomlContent.equals(currentBallerinaTomlContent);
+        }
+
         private void cleanPackageCache(DependencyGraph oldGraph,
                                        DependencyGraph newGraph) {
             io.ballerina.projects.environment.PackageCache environmentPackageCache =
@@ -711,9 +763,9 @@ private void updatePackageManifest() {
 
         private void updateDependencyManifest() {
             DependencyManifestBuilder manifestBuilder = DependencyManifestBuilder.from(
-                     Optional.ofNullable(this.dependenciesTomlContext)
-                             .map(TomlDocumentContext::tomlDocument).orElse(null),
-                     project.currentPackage().descriptor());
+                    Optional.ofNullable(this.dependenciesTomlContext)
+                            .map(TomlDocumentContext::tomlDocument).orElse(null),
+                    project.currentPackage().descriptor());
             this.dependencyManifest = manifestBuilder.dependencyManifest();
         }
 
@@ -738,25 +790,64 @@ private void updateModules() {
                     testDocContextMap.put(documentId, oldModuleContext.documentContext(documentId));
                 }
 
-                Map resourceMap = new HashMap<>();
-                for (DocumentId documentId : oldModuleContext.resourceIds()) {
-                    resourceMap.put(documentId, oldModuleContext.resourceContext(documentId));
-                }
-
-                Map testResourceMap = new HashMap<>();
-                for (DocumentId documentId : oldModuleContext.testResourceIds()) {
-                    testResourceMap.put(documentId, oldModuleContext.resourceContext(documentId));
-                }
-
                 moduleContextSet.add(new ModuleContext(this.project, moduleId, moduleDescriptor,
                         oldModuleContext.isDefaultModule(), srcDocContextMap, testDocContextMap,
                         oldModuleContext.moduleMdContext().orElse(null),
-                        oldModuleContext.moduleDescDependencies(), resourceMap, testResourceMap));
+                        oldModuleContext.moduleDescDependencies()));
                 // Remove the module with old PackageID from the compilation cache
                 PackageCache.getInstance(project.projectEnvironmentContext().getService(CompilerContext.class)).
                         remove(oldModuleContext.descriptor().moduleCompilationId());
             }
             updateModules(moduleContextSet);
         }
+
+        private Map copyResources(Package oldPackage, Collection documentIds) {
+            Map resourceContextMap = new HashMap<>();
+            for (DocumentId documentId : documentIds) {
+                resourceContextMap.put(documentId, oldPackage.packageContext.resourceContext(documentId));
+            }
+            return resourceContextMap;
+        }
+
+        /**
+         * Creates a copy of the existing module and adds a new resource to the new module.
+         *
+         * @param resourceConfig configurations to create the resource
+         * @return an instance of the Module.Modifier
+         */
+        public Package.Modifier addResource(ResourceConfig resourceConfig) {
+            ResourceContext newResourceContext = ResourceContext.from(resourceConfig);
+            this.resourceContextMap.put(newResourceContext.documentId(), newResourceContext);
+            return this;
+        }
+
+        /**
+         * Creates a copy of the existing module and adds a new test resource to the new module.
+         *
+         * @param resourceConfig configurations to create the test resource
+         * @return an instance of the Module.Modifier
+         */
+        public Package.Modifier addTestResource(ResourceConfig resourceConfig) {
+            ResourceContext newResourceContext = ResourceContext.from(resourceConfig);
+            this.testResourceContextMap.put(newResourceContext.documentId(), newResourceContext);
+            return this;
+        }
+
+        /**
+         * Creates a copy of the existing module and removes the specified resource from the new module.
+         *
+         * @param documentId documentId of the resource to remove
+         * @return an instance of the Module.Modifier
+         */
+        public Package.Modifier removeResource(DocumentId documentId) {
+
+            if (this.resourceContextMap.containsKey(documentId)) {
+                this.resourceContextMap.remove(documentId);
+            } else {
+                this.testResourceContextMap.remove(documentId);
+            }
+            return this;
+        }
+
     }
 }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageCompilation.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageCompilation.java
index 910ff1b290e4..4ee6a04af982 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageCompilation.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageCompilation.java
@@ -24,6 +24,7 @@
 import io.ballerina.projects.internal.DefaultDiagnosticResult;
 import io.ballerina.projects.internal.PackageDiagnostic;
 import io.ballerina.tools.diagnostics.Diagnostic;
+import io.ballerina.tools.diagnostics.DiagnosticSeverity;
 import org.ballerinalang.compiler.plugins.CompilerPlugin;
 import org.wso2.ballerinalang.compiler.tree.BLangPackage;
 import org.wso2.ballerinalang.compiler.util.CompilerContext;
@@ -122,9 +123,9 @@ private static PackageCompilation compile(PackageCompilation compilation) {
         return compilation;
     }
 
-    List notifyCompilationCompletion(Path filePath) {
+    List notifyCompilationCompletion(Path filePath, BalCommand balCommand) {
         CompilerLifecycleManager manager = this.compilerPluginManager.getCompilerLifecycleListenerManager();
-        List diagnostics = manager.runCodeGeneratedTasks(filePath);
+        List diagnostics = manager.runCodeGeneratedTasks(filePath, balCommand);
         this.pluginDiagnostics.addAll(diagnostics);
         return diagnostics;
     }
@@ -209,8 +210,11 @@ private void compileModulesInternal() {
             for (ModuleContext moduleContext : packageResolution.topologicallySortedModuleList()) {
                 moduleContext.compile(compilerContext);
                 for (Diagnostic diagnostic : moduleContext.diagnostics()) {
-                    diagnostics.add(new PackageDiagnostic(diagnostic, moduleContext.descriptor(),
-                            moduleContext.project()));
+                    if (!ProjectKind.BALA_PROJECT.equals(moduleContext.project().kind()) ||
+                            (diagnostic.diagnosticInfo().severity() == DiagnosticSeverity.ERROR)) {
+                        diagnostics.add(new PackageDiagnostic(diagnostic, moduleContext.descriptor(),
+                                moduleContext.project()));
+                    }
                 }
             }
         }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageConfig.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageConfig.java
index 7768172ecfeb..9ea7569e8574 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageConfig.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageConfig.java
@@ -19,6 +19,7 @@
 
 import java.nio.file.Path;
 import java.util.Collection;
+import java.util.List;
 import java.util.Optional;
 
 /**
@@ -44,6 +45,8 @@ public class PackageConfig {
     private final Collection otherModules;
     private final DocumentConfig packageMd;
     private final boolean disableSyntaxTree;
+    private final List resources;
+    private final List testResources;
 
     private PackageConfig(PackageId packageId,
                           Path packagePath,
@@ -57,7 +60,9 @@ private PackageConfig(PackageId packageId,
                           Collection moduleConfigs,
                           DependencyGraph packageDescDependencyGraph,
                           DocumentConfig packageMd,
-                          boolean disableSyntaxTree) {
+                          boolean disableSyntaxTree,
+                          List resources,
+                          List testResources) {
         this.packageId = packageId;
         this.packagePath = packagePath;
         this.packageManifest = packageManifest;
@@ -71,22 +76,8 @@ private PackageConfig(PackageId packageId,
         this.packageDescDependencyGraph = packageDescDependencyGraph;
         this.packageMd = packageMd;
         this.disableSyntaxTree = disableSyntaxTree;
-    }
-
-    public static PackageConfig from(PackageId packageId,
-                                     Path packagePath,
-                                     PackageManifest packageManifest,
-                                     DependencyManifest dependencyManifest,
-                                     DocumentConfig ballerinaToml,
-                                     DocumentConfig dependenciesToml,
-                                     DocumentConfig cloudToml,
-                                     DocumentConfig compilerPluginToml,
-                                     DocumentConfig balToolToml,
-                                     DocumentConfig packageMd,
-                                     Collection moduleConfigs) {
-        return new PackageConfig(packageId, packagePath, packageManifest, dependencyManifest, ballerinaToml,
-                                 dependenciesToml, cloudToml, compilerPluginToml, balToolToml, moduleConfigs,
-                                 DependencyGraph.emptyGraph(), packageMd, false);
+        this.resources = resources;
+        this.testResources = testResources;
     }
 
     public static PackageConfig from(PackageId packageId,
@@ -100,10 +91,12 @@ public static PackageConfig from(PackageId packageId,
                                      DocumentConfig balToolToml,
                                      DocumentConfig packageMd,
                                      Collection moduleConfigs,
-                                     DependencyGraph packageDescDependencyGraph) {
+                                     List resources,
+                                     List testResources) {
         return new PackageConfig(packageId, packagePath, packageManifest, dependencyManifest, ballerinaToml,
                                  dependenciesToml, cloudToml, compilerPluginToml, balToolToml, moduleConfigs,
-                                 packageDescDependencyGraph, packageMd, false);
+                                 DependencyGraph.emptyGraph(), packageMd, false, resources,
+                                 testResources);
     }
 
     public static PackageConfig from(PackageId packageId,
@@ -118,10 +111,26 @@ public static PackageConfig from(PackageId packageId,
                                      DocumentConfig packageMd,
                                      Collection moduleConfigs,
                                      DependencyGraph packageDescDependencyGraph,
-                                     boolean disableSyntaxTree) {
+                                     List resources,
+                                     List testResources) {
         return new PackageConfig(packageId, packagePath, packageManifest, dependencyManifest, ballerinaToml,
+                                 dependenciesToml, cloudToml, compilerPluginToml, balToolToml, moduleConfigs,
+                                 packageDescDependencyGraph, packageMd, false, resources,
+                                 testResources);
+    }
+
+    public static PackageConfig from(PackageId packageId, Path path, PackageManifest packageManifest,
+                                     DependencyManifest dependencyManifest, DocumentConfig ballerinaToml,
+                                     DocumentConfig dependenciesToml, DocumentConfig cloudToml,
+                                     DocumentConfig compilerPluginToml, DocumentConfig balToolToml,
+                                     DocumentConfig packageMd, List moduleConfigs,
+                                     DependencyGraph packageDependencyGraph,
+                                     boolean disableSyntaxTree, List resources,
+                                     List testResources) {
+        return new PackageConfig(packageId, path, packageManifest, dependencyManifest, ballerinaToml,
                 dependenciesToml, cloudToml, compilerPluginToml, balToolToml, moduleConfigs,
-                packageDescDependencyGraph, packageMd, disableSyntaxTree);
+                packageDependencyGraph, packageMd, disableSyntaxTree, resources,
+                testResources);
     }
 
     public PackageId packageId() {
@@ -197,4 +206,12 @@ public Optional dependenciesToml() {
     boolean isSyntaxTreeDisabled() {
         return disableSyntaxTree;
     }
+
+    public List resources() {
+        return resources;
+    }
+
+    public List testResources() {
+        return testResources;
+    }
 }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageContext.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageContext.java
index 842a7a9f7ee1..a646004e8ffd 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageContext.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageContext.java
@@ -52,6 +52,10 @@ class PackageContext {
 
     private final CompilationOptions compilationOptions;
     private ModuleContext defaultModuleContext;
+    private final Collection resourceIds;
+    private final Collection testResourceIds;
+    private final Map resourceContextMap;
+    private final Map testResourceContextMap;
 
     /**
      * This variable holds the dependency graph cached in a project.
@@ -80,7 +84,9 @@ class PackageContext {
                    MdDocumentContext packageMdContext,
                    CompilationOptions compilationOptions,
                    Map moduleContextMap,
-                   DependencyGraph pkgDescDependencyGraph) {
+                   DependencyGraph pkgDescDependencyGraph,
+                   Map resourceContextMap,
+                   Map testResourceContextMap) {
         this.project = project;
         this.packageId = packageId;
         this.packageManifest = packageManifest;
@@ -98,6 +104,10 @@ class PackageContext {
         this.moduleCompilationMap = new HashMap<>();
         this.packageDependencies = Collections.emptySet();
         this.pkgDescDependencyGraph = pkgDescDependencyGraph;
+        this.resourceContextMap = resourceContextMap;
+        this.testResourceContextMap = testResourceContextMap;
+        this.resourceIds = Collections.unmodifiableCollection(resourceContextMap.keySet());
+        this.testResourceIds = Collections.unmodifiableCollection(testResourceContextMap.keySet());
     }
 
     static PackageContext from(Project project, PackageConfig packageConfig, CompilationOptions compilationOptions) {
@@ -106,7 +116,15 @@ static PackageContext from(Project project, PackageConfig packageConfig, Compila
             moduleContextMap.put(moduleConfig.moduleId(), ModuleContext.from(project, moduleConfig,
                     packageConfig.isSyntaxTreeDisabled()));
         }
+        Map resourceContextMap = new HashMap<>();
+        for (ResourceConfig resourceConfig : packageConfig.resources()) {
+            resourceContextMap.put(resourceConfig.documentId(), ResourceContext.from(resourceConfig));
+        }
 
+        Map testResourceContextMap = new HashMap<>();
+        for (ResourceConfig resourceConfig : packageConfig.testResources()) {
+            testResourceContextMap.put(resourceConfig.documentId(), ResourceContext.from(resourceConfig));
+        }
         return new PackageContext(project, packageConfig.packageId(), packageConfig.packageManifest(),
                           packageConfig.dependencyManifest(),
                           packageConfig.ballerinaToml().map(TomlDocumentContext::from).orElse(null),
@@ -115,7 +133,8 @@ static PackageContext from(Project project, PackageConfig packageConfig, Compila
                           packageConfig.compilerPluginToml().map(TomlDocumentContext::from).orElse(null),
                           packageConfig.balToolToml().map(TomlDocumentContext::from).orElse(null),
                           packageConfig.packageMd().map(MdDocumentContext::from).orElse(null),
-                          compilationOptions, moduleContextMap, packageConfig.packageDescDependencyGraph());
+                          compilationOptions, moduleContextMap, packageConfig.packageDescDependencyGraph(),
+                          resourceContextMap, testResourceContextMap);
     }
 
     PackageId packageId() {
@@ -274,6 +293,13 @@ BuildToolResolution getBuildToolResolution() {
         return buildToolResolution;
     }
 
+   PackageResolution getResolution(PackageResolution oldResolution) {
+        if (packageResolution == null) {
+            packageResolution = PackageResolution.from(oldResolution, this, this.compilationOptions);
+        }
+        return packageResolution;
+    }
+
     Collection packageDependencies() {
         return packageDependencies;
     }
@@ -320,6 +346,22 @@ private void resolveModuleDependencies(ModuleContext moduleContext,
         }
     }
 
+    Collection resourceIds() {
+        return this.resourceIds;
+    }
+
+    Collection testResourceIds() {
+        return this.testResourceIds;
+    }
+
+    ResourceContext resourceContext(DocumentId documentId) {
+        if (this.resourceIds.contains(documentId)) {
+            return this.resourceContextMap.get(documentId);
+        } else {
+            return this.testResourceContextMap.get(documentId);
+        }
+    }
+
     PackageContext duplicate(Project project) {
         Map duplicatedModuleContextMap = new HashMap<>();
         for (ModuleId moduleId : this.moduleIds) {
@@ -330,6 +372,7 @@ PackageContext duplicate(Project project) {
         return new PackageContext(project, this.packageId, this.packageManifest,
                 this.dependencyManifest, this.ballerinaTomlContext, this.dependenciesTomlContext,
                 this.cloudTomlContext, this.compilerPluginTomlContext, this.balToolTomlContext, this.packageMdContext,
-                this.compilationOptions, duplicatedModuleContextMap, this.pkgDescDependencyGraph);
+                this.compilationOptions, duplicatedModuleContextMap, this.pkgDescDependencyGraph,
+                this.resourceContextMap, this.testResourceContextMap);
     }
 }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageManifest.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageManifest.java
index 3f0e234f7f47..9c31d3f47e7d 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageManifest.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageManifest.java
@@ -337,6 +337,7 @@ public boolean template() {
      * @since 2.0.0
      */
     public static class Platform {
+        public static final String GRAALVM_COMPATIBLE = "graalvmCompatible";
         // We could eventually add more things to the platform
         private final List> dependencies;
         private final List> repositories;
@@ -370,7 +371,20 @@ public List> repositories() {
         }
 
         public Boolean graalvmCompatible() {
-            return graalvmCompatible;
+                return graalvmCompatible;
+        }
+
+        public Boolean isPlatfromDepsGraalvmCompatible() {
+            Boolean overallGraalvmCompatibility = true;
+            for (Map dependency : dependencies) {
+                Boolean dependencyGraalvmCompatibility = (Boolean) dependency.get(GRAALVM_COMPATIBLE);
+                if (dependencyGraalvmCompatibility == null) {
+                    overallGraalvmCompatibility = null;
+                } else if (!dependencyGraalvmCompatibility) {
+                    return false;
+                }
+            }
+            return overallGraalvmCompatibility;
         }
     }
 
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageMd.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageMd.java
index 1cf66c0e10ef..7743cbc537d7 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageMd.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageMd.java
@@ -65,9 +65,9 @@ public Modifier modify() {
      */
     public static class Modifier {
         private String content;
-        private String name;
-        private DocumentId documentId;
-        private Package oldPackage;
+        private final String name;
+        private final DocumentId documentId;
+        private final Package oldPackage;
 
         private Modifier(PackageMd oldDocument) {
             this.content = oldDocument.mdDocumentContext.content();
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageResolution.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageResolution.java
index 687055351a1b..c59091c276ba 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageResolution.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/PackageResolution.java
@@ -49,6 +49,7 @@
 import org.wso2.ballerinalang.compiler.util.Names;
 import org.wso2.ballerinalang.util.RepoUtils;
 
+import java.io.IOException;
 import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -59,7 +60,12 @@
 import java.util.Optional;
 import java.util.stream.Collectors;
 
+import static io.ballerina.projects.util.ProjectConstants.BALLERINA_HOME;
 import static io.ballerina.projects.util.ProjectConstants.DOT;
+import static io.ballerina.projects.util.ProjectConstants.EQUAL;
+import static io.ballerina.projects.util.ProjectConstants.OFFLINE_FLAG;
+import static io.ballerina.projects.util.ProjectConstants.REPOSITORY_FLAG;
+import static io.ballerina.projects.util.ProjectConstants.STICKY_FLAG;
 
 /**
  * Resolves dependencies and handles version conflicts in the dependency graph.
@@ -92,18 +98,131 @@ private PackageResolution(PackageContext rootPackageContext, CompilationOptions
         this.blendedManifest = createBlendedManifest(rootPackageContext, projectEnvContext,
                 this.resolutionOptions.offline());
         diagnosticList.addAll(this.blendedManifest.diagnosticResult().allDiagnostics);
-
         this.moduleResolver = createModuleResolver(rootPackageContext, projectEnvContext);
         this.dependencyGraph = buildDependencyGraph();
         DependencyResolution dependencyResolution = new DependencyResolution(
                 projectEnvContext.getService(PackageCache.class), moduleResolver, dependencyGraph);
         resolveDependencies(dependencyResolution);
+        if (compilationOptions.optimizeDependencyCompilation()) {
+            generateCaches();
+        }
+    }
+
+    /**
+     * This method performs the BIR generation before the compilation by
+     * spinning up a new process.
+     * This is typically useful for large packages to avoid OOM issues.
+     */
+    private void generateCaches() {
+        for (ResolvedPackageDependency resolvedPackageDependency : this.dependencyGraph.toTopologicallySortedList()) {
+            Package packageInstance = resolvedPackageDependency.packageInstance();
+
+            // If the package instance is the current package, we have reached the root of the dependency graph.
+            // We skip the generation of the cache for the current package.
+            PackageDescriptor packageDescriptor = packageInstance.descriptor();
+            if (packageDescriptor == this.rootPackageContext.descriptor()) {
+                break;
+            }
+
+            // If the dependency is not loaded from sources, then we assume that the BIR is already generated.
+            // We skip the cache generation for the particular dependency.
+            if (packageInstance.getDefaultModule().moduleContext()
+                    .currentCompilationState() != ModuleCompilationState.LOADED_FROM_SOURCES) {
+                continue;
+            }
+
+            // We use the pull command to generate the BIR of the dependency.
+            List cmdArgs = new ArrayList<>();
+            cmdArgs.add(System.getProperty(BALLERINA_HOME) + "/bin/bal");
+            cmdArgs.add("pull");
+            cmdArgs.add(STICKY_FLAG + EQUAL + resolutionOptions.sticky());
+            cmdArgs.add(OFFLINE_FLAG + EQUAL + resolutionOptions.offline());
+
+            // Specify which repository to resolve the dependency from
+            Optional dependency =
+                    blendedManifest.userSpecifiedDependency(packageDescriptor.org(), packageDescriptor.name());
+            if (dependency.isPresent() && dependency.get().repository() != null) {
+                cmdArgs.add(REPOSITORY_FLAG + EQUAL + dependency.get().repository());
+            }
+            cmdArgs.add(packageDescriptor.toString());
+
+            ProcessBuilder processBuilder = new ProcessBuilder(cmdArgs);
+            try {
+                Process process = processBuilder.start();
+                int i = process.waitFor();
+                if (i != 0) {
+                    String errMessage = packageDescriptor.toString();
+                    if (dependency.isPresent()) {
+                        errMessage += " [repository=" + dependency.get().repository() + "]";
+                    }
+                    throw new ProjectException("failed to compile " + errMessage);
+                }
+            } catch (IOException | InterruptedException e) {
+                throw new ProjectException(e);
+            }
+
+            // Finally, we set the compilation state of the dependency to LOADED_FROM_CACHE
+            for (ModuleId moduleId : packageInstance.moduleIds()) {
+                packageInstance.module(moduleId).moduleContext()
+                        .setCompilationState(ModuleCompilationState.LOADED_FROM_CACHE);
+            }
+        }
+    }
+
+    private PackageResolution(PackageResolution packageResolution, PackageContext rootPackageContext,
+                              CompilationOptions compilationOptions) {
+        this.rootPackageContext = rootPackageContext;
+        this.diagnosticList = new ArrayList<>();
+        this.compilationOptions = compilationOptions;
+        this.resolutionOptions = getResolutionOptions(rootPackageContext, compilationOptions);
+        ProjectEnvironment projectEnvContext = rootPackageContext.project().projectEnvironmentContext();
+        this.packageResolver = projectEnvContext.getService(PackageResolver.class);
+        this.blendedManifest = createBlendedManifest(rootPackageContext, projectEnvContext,
+                this.resolutionOptions.offline());
+        diagnosticList.addAll(this.blendedManifest.diagnosticResult().allDiagnostics);
+        this.moduleResolver = createModuleResolver(rootPackageContext, projectEnvContext);
+        LinkedHashSet moduleLoadRequests = getModuleLoadRequestsOfDirectDependencies();
+        moduleResolver.resolveModuleLoadRequests(moduleLoadRequests);
+        this.dependencyGraph = cloneDependencyGraphNewRoot(packageResolution.dependencyGraph,
+                rootPackageContext.project().currentPackage());
+        this.dependencyGraphDump = packageResolution.dependencyGraphDump;
+        DependencyResolution dependencyResolution = new DependencyResolution(
+                projectEnvContext.getService(PackageCache.class), moduleResolver, dependencyGraph);
+        resolveDependencies(dependencyResolution);
+    }
+
+    private DependencyGraph cloneDependencyGraphNewRoot
+            (DependencyGraph depGraph, Package rootPackage) {
+        ResolvedPackageDependency oldRoot = depGraph.getRoot();
+        ResolvedPackageDependency newRoot = new ResolvedPackageDependency(rootPackage,
+                oldRoot.scope(), oldRoot.dependencyResolvedType());
+        DependencyGraphBuilder depGraphBuilder =
+                DependencyGraphBuilder.getBuilder(newRoot);
+        for (ResolvedPackageDependency depNode : depGraph.getNodes()) {
+            if (depNode == oldRoot) {
+                depGraphBuilder.add(newRoot);
+            } else {
+                depGraphBuilder.add(depNode);
+            }
+            List directPkgDependencies =
+                    depGraph.getDirectDependencies(depNode)
+                            .stream()
+                            .map(directDepNode -> directDepNode == oldRoot ? newRoot : directDepNode)
+                            .collect(Collectors.toList());
+            depGraphBuilder.addDependencies(depNode, directPkgDependencies);
+        }
+        return depGraphBuilder.build();
     }
 
     static PackageResolution from(PackageContext rootPackageContext, CompilationOptions compilationOptions) {
         return new PackageResolution(rootPackageContext, compilationOptions);
     }
 
+    static PackageResolution from(PackageResolution packageResolution, PackageContext
+            packageContext, CompilationOptions compilationOptions) {
+        return new PackageResolution(packageResolution, packageContext, compilationOptions);
+    }
+
     /**
      * Returns the package dependency graph of this package.
      *
@@ -127,7 +246,7 @@ public Collection allDependencies() {
                 .stream()
                 // Remove root package from this list.
                 .filter(resolvedPkg -> resolvedPkg.packageId() != rootPackageContext.packageId())
-                .collect(Collectors.toList());
+                .toList();
         return dependenciesWithTransitives;
     }
 
@@ -184,7 +303,7 @@ public boolean autoUpdate() {
      */
     private DependencyGraph buildDependencyGraph() {
         // TODO We should get diagnostics as well. Need to design that contract
-        if (rootPackageContext.project().kind() == ProjectKind.BALA_PROJECT) {
+        if (rootPackageContext.project().kind() == ProjectKind.BALA_PROJECT && this.resolutionOptions.sticky()) {
             return resolveBALADependencies();
         } else {
             return resolveSourceDependencies();
@@ -291,7 +410,7 @@ private DependencyGraph buildPackageGraph(DependencyG
                 .filter(depNode -> !depNode.equals(rootNode) // Remove root node from the requests
                         && !depNode.errorNode()) // Remove error nodes from the requests
                 .map(this::createFromDepNode)
-                .collect(Collectors.toList());
+                .toList();
         Collection resolutionResponses =
                 packageResolver.resolvePackages(resolutionRequests, resolutionOptions);
 
@@ -328,7 +447,7 @@ private DependencyGraph buildPackageGraph(DependencyG
                                 .map(directDepNode -> resolvedPkgContainer.get(
                                         directDepNode.pkgDesc().org(), directDepNode.pkgDesc().name()))
                                 .flatMap(Optional::stream)
-                                .collect(Collectors.toList());
+                                .toList();
                 depGraphBuilder.addDependencies(resolvedPkg, directPkgDependencies);
             }
         }
@@ -385,7 +504,7 @@ private void resolveDependencies(DependencyResolution dependencyResolution) {
         // Repeat this for each module in each package in the package dependency graph.
         List sortedModuleList = new ArrayList<>();
         List sortedPackages = dependencyGraph.toTopologicallySortedList();
-        if (dependencyGraph.findCycles().size() > 0) {
+        if (!dependencyGraph.findCycles().isEmpty()) {
             for (List cycle: dependencyGraph.findCycles()) {
                 DiagnosticInfo diagnosticInfo = new DiagnosticInfo(
                         DiagnosticErrorCode.CYCLIC_MODULE_IMPORTS_DETECTED.diagnosticId(),
@@ -405,7 +524,7 @@ private void resolveDependencies(DependencyResolution dependencyResolution) {
             DependencyGraph moduleDependencyGraph = resolvedPackage.moduleDependencyGraph();
             List sortedModuleDescriptors
                     = moduleDependencyGraph.toTopologicallySortedList();
-            if (moduleDependencyGraph.findCycles().size() > 0) {
+            if (!moduleDependencyGraph.findCycles().isEmpty()) {
                 for (List cycle: moduleDependencyGraph.findCycles()) {
                     DiagnosticInfo diagnosticInfo = new DiagnosticInfo(
                             DiagnosticErrorCode.CYCLIC_MODULE_IMPORTS_DETECTED.diagnosticId(),
@@ -433,7 +552,7 @@ private ModuleResolver createModuleResolver(PackageContext rootPackageContext,
         List moduleNames = rootPackageContext.moduleIds().stream()
                 .map(rootPackageContext::moduleContext)
                 .map(ModuleContext::moduleName)
-                .collect(Collectors.toList());
+                .toList();
         return new ModuleResolver(rootPackageContext.descriptor(), moduleNames, blendedManifest,
                 projectEnvContext.getService(PackageResolver.class), resolutionOptions);
     }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Project.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Project.java
index 32807620ef96..9a8566454c14 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Project.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Project.java
@@ -42,7 +42,7 @@ public abstract class Project {
     protected ProjectEnvironment projectEnvironment;
     private final ProjectKind projectKind;
     private Map toolContextMap;
-    private List compilerPluginContexts;
+    private final List compilerPluginContexts;
 
     protected Project(ProjectKind projectKind,
                       Path projectPath,
@@ -88,6 +88,8 @@ public Path sourceRoot() {
 
     public abstract Path targetDir();
 
+    public abstract Path generatedResourcesDir();
+
     protected void setCurrentPackage(Package currentPackage) {
         // TODO Handle concurrent read/write to the currentPackage variable
         this.currentPackage = currentPackage;
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ProjectEnvironmentBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ProjectEnvironmentBuilder.java
index 2f753a110783..6c37a0f6de9b 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ProjectEnvironmentBuilder.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ProjectEnvironmentBuilder.java
@@ -59,18 +59,12 @@ public ProjectEnvironment build(Project project) {
         if (compilationCacheFactory != null) {
             compilationCache = compilationCacheFactory.createCompilationCache(project);
         } else {
-            switch (project.kind()) {
-                case BUILD_PROJECT:
-                    compilationCache = BuildProjectCompilationCache.from(project);
-                    break;
-                case SINGLE_FILE_PROJECT:
-                    compilationCache = TempDirCompilationCache.from(project);
-                    break;
-                case BALA_PROJECT:
-                    throw new IllegalStateException("BALAProject should always be created with a CompilationCache");
-                default:
-                    throw new UnsupportedOperationException("Unsupported ProjectKind: " + project.kind());
-            }
+            compilationCache = switch (project.kind()) {
+                case BUILD_PROJECT -> BuildProjectCompilationCache.from(project);
+                case SINGLE_FILE_PROJECT -> TempDirCompilationCache.from(project);
+                case BALA_PROJECT ->
+                        throw new IllegalStateException("BALAProject should always be created with a CompilationCache");
+            };
         }
         services.put(CompilationCache.class, compilationCache);
         return new DefaultProjectEnvironment(project, environment, services);
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ProjectKind.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ProjectKind.java
index b4416baf544d..27dd44f3f4d4 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ProjectKind.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/ProjectKind.java
@@ -29,5 +29,4 @@ public enum ProjectKind {
     BUILD_PROJECT,
     SINGLE_FILE_PROJECT,
     BALA_PROJECT,
-    ;
 }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Resource.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Resource.java
index e520c3f0984c..289e69ebd72a 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Resource.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/Resource.java
@@ -25,16 +25,16 @@
 public class Resource {
 
     private final ResourceContext resourceContext;
-    private final Module module;
+    private final Package packageInstance;
 
-    Resource(ResourceContext resourceContext, Module module) {
+    Resource(ResourceContext resourceContext, Package aPackage) {
         this.resourceContext = resourceContext;
-        this.module = module;
+        this.packageInstance = aPackage;
     }
 
-    Resource from(ResourceConfig resourceConfig, Module module) {
+    Resource from(ResourceConfig resourceConfig, Package aPackage) {
         ResourceContext resourceContext = ResourceContext.from(resourceConfig);
-        return new Resource(resourceContext, module);
+        return new Resource(resourceContext, aPackage);
     }
 
     public DocumentId documentId() {
@@ -49,7 +49,12 @@ public byte[] content() {
         return resourceContext.content();
     }
 
+    @Deprecated(since = "2201.10.0", forRemoval = true)
     public Module module() {
-        return module;
+        return packageInstance.getDefaultModule();
+    }
+
+    public Package packageInstance() {
+        return packageInstance;
     }
 }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/SemanticVersion.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/SemanticVersion.java
index 812cd55615a1..4efa06bee1c9 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/SemanticVersion.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/SemanticVersion.java
@@ -159,6 +159,6 @@ public enum VersionCompatibilityResult {
         INCOMPATIBLE,
         EQUAL,
         LESS_THAN,
-        GREATER_THAN;
+        GREATER_THAN
     }
 }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/SettingsToml.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/SettingsToml.java
index a1773b761c1d..26b6e58d398f 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/SettingsToml.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/SettingsToml.java
@@ -27,7 +27,7 @@
  */
 public class SettingsToml {
 
-    private TomlDocumentContext settingsTomlContext;
+    private final TomlDocumentContext settingsTomlContext;
 
     private SettingsToml(TomlDocumentContext tomlDocumentContext) {
         this.settingsTomlContext = tomlDocumentContext;
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/SyntaxTreeVisitor.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/SyntaxTreeVisitor.java
index 264de4b88ae3..d6acec14622a 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/SyntaxTreeVisitor.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/SyntaxTreeVisitor.java
@@ -69,6 +69,7 @@ List runAnalysisTasks() {
         return diagnostics;
     }
 
+    @Override
     protected void visitSyntaxNode(Node node) {
         // We don't support syntax kinds related to Tokens
         if (node instanceof Token) {
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/TestEmitArgs.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/TestEmitArgs.java
new file mode 100644
index 000000000000..a045b00e25c3
--- /dev/null
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/TestEmitArgs.java
@@ -0,0 +1,42 @@
+// 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.projects;
+
+import java.nio.file.Path;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Record for storing arguments to use in JBallerinaBackend's emit of TEST.
+ *
+ * @since 2201.9.0
+ */
+
+/**
+ * Record for storing arguments to use in JBallerinaBackend's emit of TEST.
+ * @param outputType    Output type to indicate the type of the emitting output
+ * @param filePath      File path to specify where the output should be emitted
+ * @param jarDependencies   Jar dependencies required for emitting the output
+ * @param testSuiteJsonPath Path to the test suite json that should be packed inside the output
+ * @param jsonCopyPath      The path inside the output where the test suite json should be copied
+ * @param excludedClasses   List of excluded classes
+ * @param classPathTextCopyPath Path inside the output where the class path text should be copied
+ */
+public record TestEmitArgs(JBallerinaBackend.OutputType outputType, Path filePath, HashSet jarDependencies,
+                           Path testSuiteJsonPath, String jsonCopyPath, List excludedClasses,
+                           String classPathTextCopyPath) {
+}
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/TomlDocumentContext.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/TomlDocumentContext.java
index afa9c4a001a4..84f2d1a5daba 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/TomlDocumentContext.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/TomlDocumentContext.java
@@ -25,7 +25,7 @@
  * @since 2.0.0
  */
 public class TomlDocumentContext {
-    private TomlDocument tomlDocument;
+    private final TomlDocument tomlDocument;
 
     private TomlDocumentContext(TomlDocument tomlDocument) {
         this.tomlDocument = tomlDocument;
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/bala/BalaProject.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/bala/BalaProject.java
index 81febf8d9c61..282079a6df1c 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/bala/BalaProject.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/bala/BalaProject.java
@@ -18,6 +18,7 @@
 
 package io.ballerina.projects.bala;
 
+import io.ballerina.projects.BuildOptions;
 import io.ballerina.projects.Document;
 import io.ballerina.projects.DocumentId;
 import io.ballerina.projects.Module;
@@ -53,13 +54,21 @@ public class BalaProject extends Project {
      */
     public static BalaProject loadProject(ProjectEnvironmentBuilder environmentBuilder, Path balaPath) {
         PackageConfig packageConfig = PackageConfigCreator.createBalaProjectConfig(balaPath);
-        BalaProject balaProject = new BalaProject(environmentBuilder, balaPath);
+        BalaProject balaProject = new BalaProject(environmentBuilder, balaPath, BuildOptions.builder().build());
         balaProject.addPackage(packageConfig);
         return balaProject;
     }
 
-    private BalaProject(ProjectEnvironmentBuilder environmentBuilder, Path balaPath) {
-        super(ProjectKind.BALA_PROJECT, balaPath, environmentBuilder);
+    public static BalaProject loadProject(ProjectEnvironmentBuilder environmentBuilder, Path balaPath,
+                                          BuildOptions buildOptions) {
+        PackageConfig packageConfig = PackageConfigCreator.createBalaProjectConfig(balaPath);
+        BalaProject balaProject = new BalaProject(environmentBuilder, balaPath, buildOptions);
+        balaProject.addPackage(packageConfig);
+        return balaProject;
+    }
+
+    private BalaProject(ProjectEnvironmentBuilder environmentBuilder, Path balaPath, BuildOptions buildOptions) {
+        super(ProjectKind.BALA_PROJECT, balaPath, environmentBuilder, buildOptions);
         this.platform = BalaFiles.readPackageJson(balaPath).getPlatform();
     }
 
@@ -75,7 +84,8 @@ public void clearCaches() {
     public Project duplicate() {
         ProjectEnvironmentBuilder projectEnvironmentBuilder = ProjectEnvironmentBuilder.getDefaultBuilder();
         projectEnvironmentBuilder.addCompilationCacheFactory(TempDirCompilationCache::from);
-        BalaProject balaProject = new BalaProject(projectEnvironmentBuilder, this.sourceRoot);
+        BuildOptions duplicateBuildOptions = BuildOptions.builder().build().acceptTheirs(buildOptions());
+        BalaProject balaProject = new BalaProject(projectEnvironmentBuilder, this.sourceRoot, duplicateBuildOptions);
         return resetPackage(balaProject);
     }
 
@@ -139,4 +149,9 @@ private boolean isFilePathInProject(Path filepath) {
     public Path targetDir() {
         throw new UnsupportedOperationException("target directory is not supported for BalaProject");
     }
+
+    @Override
+    public Path generatedResourcesDir() {
+        throw new UnsupportedOperationException("generated resources directory is not supported for BalaProject");
+    }
 }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/directory/BuildProject.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/directory/BuildProject.java
index b12d9c6bce15..79b3a743830c 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/directory/BuildProject.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/directory/BuildProject.java
@@ -51,7 +51,6 @@
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -254,7 +253,7 @@ public DocumentId documentId(Path file) {
                 }
             }
         }
-        throw new ProjectException("provided path does not belong to the project");
+        throw new ProjectException("'" + file.toString() + "' does not belong to the current project");
     }
 
     private boolean isFilePathInProject(Path filepath) {
@@ -266,6 +265,7 @@ private boolean isFilePathInProject(Path filepath) {
         return true;
     }
 
+    @Override
     public void save() {
         Path buildFilePath = this.targetDir().resolve(BUILD_FILE);
         boolean shouldUpdate = this.currentPackage().getResolution().autoUpdate();
@@ -522,7 +522,20 @@ public Path targetDir() {
         if (this.buildOptions().getTargetPath() == null) {
             return this.sourceRoot.resolve(ProjectConstants.TARGET_DIR_NAME);
         } else {
-            return Paths.get(this.buildOptions().getTargetPath());
+            return Path.of(this.buildOptions().getTargetPath());
+        }
+    }
+
+    @Override
+    public Path generatedResourcesDir() {
+        Path generatedResourcesPath = targetDir().resolve(ProjectConstants.RESOURCE_DIR_NAME);
+        if (!Files.exists(generatedResourcesPath)) {
+            try {
+                Files.createDirectories(generatedResourcesPath);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
         }
+        return generatedResourcesPath;
     }
 }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/directory/ProjectLoader.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/directory/ProjectLoader.java
index a4744b81c66b..baf85563d5a2 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/directory/ProjectLoader.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/directory/ProjectLoader.java
@@ -35,7 +35,10 @@
  *
  * @since 2.0.0
  */
-public class ProjectLoader {
+public final class ProjectLoader {
+
+    private ProjectLoader() {
+    }
 
     public static Project loadProject(Path path) {
         return loadProject(path, ProjectEnvironmentBuilder.getDefaultBuilder(), BuildOptions.builder().build());
@@ -81,7 +84,7 @@ public static Project loadProject(Path path, ProjectEnvironmentBuilder projectEn
                 return BuildProject.load(projectEnvironmentBuilder, projectRoot, buildOptions);
             } else if (Files.exists(projectRoot.resolve(ProjectConstants.PACKAGE_JSON))) {
                 projectEnvironmentBuilder.addCompilationCacheFactory(TempDirCompilationCache::from);
-                return BalaProject.loadProject(projectEnvironmentBuilder, projectRoot);
+                return BalaProject.loadProject(projectEnvironmentBuilder, projectRoot, buildOptions);
             } else {
                 throw new ProjectException("provided directory does not belong to any supported project types");
             }
@@ -92,7 +95,7 @@ public static Project loadProject(Path path, ProjectEnvironmentBuilder projectEn
         }
 
         if (!ProjectPaths.isBalFile(absFilePath)) {
-            throw new ProjectException("provided path is not a valid Ballerina source file");
+            throw new ProjectException("'" + absFilePath + "' is not a valid Ballerina source file");
         }
 
         try {
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/directory/SingleFileProject.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/directory/SingleFileProject.java
index 9b594e8e5caa..599d9afc9347 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/directory/SingleFileProject.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/directory/SingleFileProject.java
@@ -26,6 +26,7 @@
 import io.ballerina.projects.ProjectKind;
 import io.ballerina.projects.internal.PackageConfigCreator;
 import io.ballerina.projects.repos.TempDirCompilationCache;
+import io.ballerina.projects.util.ProjectConstants;
 
 import java.io.IOException;
 import java.nio.file.Files;
@@ -51,7 +52,7 @@ public static SingleFileProject load(ProjectEnvironmentBuilder environmentBuilde
     }
 
     public static SingleFileProject load(ProjectEnvironmentBuilder environmentBuilder, Path filePath,
-                                          BuildOptions buildOptions) {
+                                         BuildOptions buildOptions) {
         PackageConfig packageConfig = PackageConfigCreator.createSingleFileProjectConfig(filePath);
         SingleFileProject singleFileProject = new SingleFileProject(
                 environmentBuilder, filePath, buildOptions);
@@ -104,7 +105,7 @@ public Project duplicate() {
     public DocumentId documentId(Path file) {
         if (!this.sourceRoot.toAbsolutePath().normalize().toString().equals(
                 file.toAbsolutePath().normalize().toString())) {
-            throw new ProjectException("provided path does not belong to the project");
+            throw new ProjectException("'" + file + "' does not belong to the current project");
         }
         return this.currentPackage().getDefaultModule().documentIds().iterator().next();
     }
@@ -125,4 +126,17 @@ public void save() {
     public Path targetDir() {
         return this.targetDir;
     }
+
+    @Override
+    public Path generatedResourcesDir() {
+        Path generatedResourcesPath = this.targetDir.resolve(ProjectConstants.RESOURCE_DIR_NAME);
+        if (!Files.exists(generatedResourcesPath)) {
+            try {
+                Files.createDirectories(generatedResourcesPath);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        return generatedResourcesPath;
+    }
 }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/environment/PackageCache.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/environment/PackageCache.java
index 176f48297663..1bae207e9146 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/environment/PackageCache.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/environment/PackageCache.java
@@ -45,7 +45,7 @@ public interface PackageCache {
      * Returns the package with the given {@code PackageId} or throw an {@code IllegalStateException}.
      *
      * @param packageId the packageId
-     * @return the package with the given {@code PackageId} or throw an {@code IllegalStateException.
+     * @return the package with the given {@code PackageId} or throw an {@code IllegalStateException}.
      */
     Package getPackageOrThrow(PackageId packageId);
 
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/BalToolsManifestBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/BalToolsManifestBuilder.java
index 0ec73e7c110f..daca246ac75c 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/BalToolsManifestBuilder.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/BalToolsManifestBuilder.java
@@ -53,7 +53,7 @@ public class BalToolsManifestBuilder {
     private final Map oldTools;
 
     private BalToolsManifestBuilder(TomlDocument balToolsToml) {
-        oldTools = new HashMap();
+        oldTools = new HashMap<>();
         this.balToolsToml = Optional.ofNullable(balToolsToml);
         this.balToolsManifest = parseAsBalToolsManifest();
     }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/BalaFiles.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/BalaFiles.java
index 8a0abb8d2f53..466ba29d1736 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/BalaFiles.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/BalaFiles.java
@@ -50,7 +50,6 @@
 import java.nio.file.FileSystems;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -82,7 +81,8 @@
  *
  * @since 2.0.0
  */
-public class BalaFiles {
+public final class BalaFiles {
+
     private static final Gson gson = new Gson();
 
     // TODO change class name to utils
@@ -105,7 +105,13 @@ private static PackageData loadPackageDataFromBalaDir(Path balaPath, PackageMani
                 .resolve(ProjectConstants.PACKAGE_MD_FILE_NAME));
         // load other modules
         List otherModules = loadOtherModules(pkgName, balaPath);
-        return PackageData.from(balaPath, defaultModule, otherModules, null, null, null, null, null, packageMd);
+        List resources = loadResources(balaPath);
+        if (resources.isEmpty()) {
+            // get resources from default module path - to support balas before 2201.10.0
+            resources = loadResources(balaPath.resolve(MODULES_ROOT).resolve(pkgName));
+        }
+        return PackageData.from(balaPath, defaultModule, otherModules, null, null,
+                null, null, null, packageMd, resources, Collections.emptyList());
     }
 
     private static PackageData loadPackageDataFromBalaFile(Path balaPath, PackageManifest packageManifest) {
@@ -119,7 +125,13 @@ private static PackageData loadPackageDataFromBalaFile(Path balaPath, PackageMan
                     .resolve(ProjectConstants.PACKAGE_MD_FILE_NAME));
             // load other modules
             List otherModules = loadOtherModules(pkgName, packageRoot);
-            return PackageData.from(balaPath, defaultModule, otherModules, null, null, null, null, null, packageMd);
+            List resources = loadResources(packageRoot);
+            if (resources.isEmpty()) {
+                // get resources from default module path - to support bala files before 2201.10.0
+                resources = loadResources(packageRoot.resolve(MODULES_ROOT).resolve(pkgName));
+            }
+            return PackageData.from(balaPath, defaultModule, otherModules, null, null,
+                    null, null, null, packageMd, resources, Collections.emptyList());
         } catch (IOException e) {
             throw new ProjectException("Failed to read bala file:" + balaPath);
         }
@@ -151,7 +163,7 @@ public static DocumentData loadDocument(Path documentFilePath) {
         }
     }
 
-    private static ModuleData loadModule(String pkgName, String fullModuleName,  Path packagePath) {
+    private static ModuleData loadModule(String pkgName, String fullModuleName, Path packagePath) {
         Path modulePath = packagePath.resolve(MODULES_ROOT).resolve(fullModuleName);
         Path moduleDocPath = packagePath.resolve(BALA_DOCS_DIR).resolve(MODULES_ROOT).resolve(fullModuleName);
         // check module path exists
@@ -178,10 +190,8 @@ private static ModuleData loadModule(String pkgName, String fullModuleName,  Pat
         List srcDocs = loadDocuments(modulePath);
         List testSrcDocs = Collections.emptyList();
         DocumentData moduleMd = loadDocument(moduleDocPath.resolve(ProjectConstants.MODULE_MD_FILE_NAME));
-        List resources = loadResources(modulePath);
 
-        return ModuleData.from(modulePath, moduleName, srcDocs, testSrcDocs, moduleMd, resources,
-                Collections.emptyList());
+        return ModuleData.from(modulePath, moduleName, srcDocs, testSrcDocs, moduleMd);
     }
 
     private static List loadOtherModules(String pkgName, Path packagePath) {
@@ -194,7 +204,7 @@ private static List loadOtherModules(String pkgName, Path packagePat
                     .filter(Files::isDirectory)
                     .map(modulePath -> modulePath.getFileName().toString())
                     .map(fullModuleName -> loadModule(pkgName, fullModuleName, packagePath))
-                    .collect(Collectors.toList());
+                    .toList();
         } catch (IOException e) {
             throw new ProjectException("Failed to read modules from directory: " + modulesDirPath, e);
         }
@@ -376,7 +386,7 @@ private static void extractPlatformLibraries(PackageJson packageJson, Path balaP
     }
 
     private static void extractCompilerPluginLibraries(CompilerPluginJson compilerPluginJson, Path balaPath,
-            FileSystem zipFileSystem) {
+                                                       FileSystem zipFileSystem) {
         if (compilerPluginJson.dependencyPaths() == null) {
             return;
         }
@@ -387,9 +397,9 @@ private static void extractCompilerPluginLibraries(CompilerPluginJson compilerPl
                 try {
                     Files.createDirectories(libPath.getParent());
                     // TODO: Need to refactor this fix
-                    Path libPathInZip = Paths.get(dependencyPath);
+                    Path libPathInZip = Path.of(dependencyPath);
                     if (!dependencyPath.contains(COMPILER_PLUGIN_DIR)) {
-                        libPathInZip = Paths.get(COMPILER_PLUGIN_DIR, String.valueOf(libPathInZip));
+                        libPathInZip = Path.of(COMPILER_PLUGIN_DIR, String.valueOf(libPathInZip));
                     }
                     Files.copy(zipFileSystem.getPath(String.valueOf(libPathInZip)), libPath);
                 } catch (IOException e) {
@@ -413,9 +423,9 @@ private static void extractBalToolLibraries(Optional balToolJson, P
             if (!Files.exists(libPath)) {
                 try {
                     Files.createDirectories(libPath.getParent());
-                    Path libPathInZip = Paths.get(dependencyPath);
+                    Path libPathInZip = Path.of(dependencyPath);
                     if (!dependencyPath.contains(TOOL_DIR)) {
-                        libPathInZip = Paths.get(TOOL_DIR, String.valueOf(libPathInZip));
+                        libPathInZip = Path.of(TOOL_DIR, String.valueOf(libPathInZip));
                     }
                     Files.copy(zipFileSystem.getPath(String.valueOf(libPathInZip)), libPath);
                 } catch (IOException e) {
@@ -452,7 +462,8 @@ private static void setBalToolDependencyPaths(BalToolJson balToolJson, Path bala
     }
 
     private static PackageManifest getPackageManifest(PackageJson packageJson,
-            Optional compilerPluginJson, Optional balToolJson, String deprecationMsg) {
+                                                      Optional compilerPluginJson,
+                                                      Optional balToolJson, String deprecationMsg) {
         PackageDescriptor pkgDesc;
         if (deprecationMsg != null) {
             pkgDesc = PackageDescriptor.from(PackageOrg.from(packageJson.getOrganization()),
@@ -518,20 +529,20 @@ private static DependencyManifest getDependencyManifest(DependencyGraphJson depe
             if (dependency.getModules() != null && !dependency.getModules().isEmpty()) {
                 for (io.ballerina.projects.internal.model.Dependency.Module depModule : dependency.getModules()) {
                     DependencyManifest.Module module = new DependencyManifest.Module(depModule.org(),
-                                                                                     depModule.packageName(),
-                                                                                     depModule.moduleName());
+                            depModule.packageName(),
+                            depModule.moduleName());
                     modules.add(module);
                 }
             }
 
             DependencyManifest.Package pkg = new
                     DependencyManifest.Package(PackageName.from(dependency.getName()),
-                                               PackageOrg.from(dependency.getOrg()),
-                                               PackageVersion.from(dependency.getVersion()),
-                                               dependency.getScope() != null ? dependency.getScope().name() : null,
-                                               dependency.isTransitive(),
-                                               dependencies,
-                                               modules);
+                    PackageOrg.from(dependency.getOrg()),
+                    PackageVersion.from(dependency.getVersion()),
+                    dependency.getScope() != null ? dependency.getScope().name() : null,
+                    dependency.isTransitive(),
+                    dependencies,
+                    modules);
             packages.add(pkg);
         }
         return DependencyManifest.from(null, null, packages, Collections.emptyList());
@@ -642,7 +653,7 @@ private static ModuleDescriptor getModuleDescriptorFromDependencyEntry(ModuleDep
     private static List createModDescriptorList(List modDepEntries) {
         return modDepEntries.stream()
                 .map(BalaFiles::getModuleDescriptorFromDependencyEntry)
-                .collect(Collectors.toList());
+                .toList();
     }
 
     private static DependencyGraphJson readDependencyGraphJson(Path dependencyGraphJsonPath) {
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/BlendedManifest.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/BlendedManifest.java
index 7cb06b7c2dd1..f8387d892b41 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/BlendedManifest.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/BlendedManifest.java
@@ -38,7 +38,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.stream.Collectors;
 
 import static io.ballerina.projects.PackageVersion.BUILTIN_PACKAGE_VERSION;
 
@@ -187,7 +186,7 @@ private static Collection moduleNames(DependencyManifest.Package depende
         return dependency.modules()
                 .stream()
                 .map(DependencyManifest.Module::moduleName)
-                .collect(Collectors.toList());
+                .toList();
     }
 
     private static Collection moduleNames(PackageManifest.Dependency dependency,
@@ -196,7 +195,7 @@ private static Collection moduleNames(PackageManifest.Dependency depende
                 dependency.org(), dependency.name(), dependency.version());
         return moduleDescriptors.stream()
                 .map(moduleDesc -> moduleDesc.name().toString())
-                .collect(Collectors.toList());
+                .toList();
     }
 
     public Optional lockedDependency(PackageOrg org, PackageName name) {
@@ -235,7 +234,7 @@ private Optional dependency(PackageOrg org, PackageName name, Depend
     private Collection dependencies(DependencyOrigin origin) {
         return depContainer.getAll().stream()
                 .filter(dep -> dep.origin == origin)
-                .collect(Collectors.toList());
+                .toList();
     }
 
     public DiagnosticResult diagnosticResult() {
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/CompilerPhaseRunner.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/CompilerPhaseRunner.java
index 3163dfd71121..5699656bceca 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/CompilerPhaseRunner.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/CompilerPhaseRunner.java
@@ -19,7 +19,6 @@
 
 import io.ballerina.runtime.internal.util.RuntimeUtils;
 import org.ballerinalang.compiler.CompilerPhase;
-import org.wso2.ballerinalang.compiler.PackageCache;
 import org.wso2.ballerinalang.compiler.bir.BIRGen;
 import org.wso2.ballerinalang.compiler.bir.emit.BIREmitter;
 import org.wso2.ballerinalang.compiler.desugar.ConstantPropagation;
@@ -33,7 +32,6 @@
 import org.wso2.ballerinalang.compiler.semantics.analyzer.SemanticAnalyzer;
 import org.wso2.ballerinalang.compiler.semantics.analyzer.SymbolEnter;
 import org.wso2.ballerinalang.compiler.semantics.analyzer.SymbolResolver;
-import org.wso2.ballerinalang.compiler.semantics.model.SymbolTable;
 import org.wso2.ballerinalang.compiler.tree.BLangPackage;
 import org.wso2.ballerinalang.compiler.util.CompilerContext;
 import org.wso2.ballerinalang.compiler.util.CompilerOptions;
@@ -53,8 +51,6 @@ public class CompilerPhaseRunner {
             new CompilerContext.Key<>();
 
     private final CompilerOptions options;
-    private final PackageCache pkgCache;
-    private final SymbolTable symbolTable;
     private final SymbolEnter symbolEnter;
     private final SymbolResolver symResolver;
     private final SemanticAnalyzer semAnalyzer;
@@ -68,7 +64,7 @@ public class CompilerPhaseRunner {
     private final CompilerPhase compilerPhase;
     private final DataflowAnalyzer dataflowAnalyzer;
     private final IsolationAnalyzer isolationAnalyzer;
-    private boolean isToolingCompilation;
+    private final boolean isToolingCompilation;
 
 
     public static CompilerPhaseRunner getInstance(CompilerContext context) {
@@ -83,8 +79,6 @@ private CompilerPhaseRunner(CompilerContext context) {
         context.put(COMPILER_DRIVER_KEY, this);
 
         this.options = CompilerOptions.getInstance(context);
-        this.pkgCache = PackageCache.getInstance(context);
-        this.symbolTable = SymbolTable.getInstance(context);
         this.symbolEnter = SymbolEnter.getInstance(context);
         this.semAnalyzer = SemanticAnalyzer.getInstance(context);
         this.symResolver = SymbolResolver.getInstance(context);
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/DependencyManifestBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/DependencyManifestBuilder.java
index d6f6f7ae294e..db383cc6e2fb 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/DependencyManifestBuilder.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/DependencyManifestBuilder.java
@@ -84,7 +84,19 @@ private DependencyManifestBuilder(TomlDocument dependenciesToml,
         this.dependenciesToml = Optional.ofNullable(dependenciesToml);
         this.packageDescriptor = packageDescriptor;
         this.diagnosticList = new ArrayList<>();
-        this.dependencyManifest = parseAsDependencyManifest();
+        DependencyManifest parsedDependecyManifest = parseAsDependencyManifest();
+        if (parsedDependecyManifest.diagnostics().hasErrors()) {
+            var diagnosticInfo = new DiagnosticInfo(
+                    ProjectDiagnosticErrorCode.CORRUPTED_DEPENDENCIES_TOML.diagnosticId(),
+                    "Detected corrupted 'Dependencies.toml' file. Dependencies will be updated to the latest versions.",
+                    DiagnosticSeverity.WARNING);
+            var diagnostic = DiagnosticFactory.createDiagnostic(diagnosticInfo,
+                    this.dependenciesToml.get().toml().rootNode().location());
+            this.dependencyManifest = DependencyManifest.from(null, null,
+                    Collections.emptyList(), Collections.emptyList(), new DefaultDiagnosticResult(List.of(diagnostic)));
+        } else {
+            this.dependencyManifest = parsedDependecyManifest;
+        }
     }
 
     public static DependencyManifestBuilder from(TomlDocument dependenciesToml,
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/DependencyVersionKind.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/DependencyVersionKind.java
index 066391b862eb..fcbaee35139a 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/DependencyVersionKind.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/DependencyVersionKind.java
@@ -36,5 +36,4 @@ public enum DependencyVersionKind {
      * Indicates that the dependency version is resolved by the package resolver.
      */
     LATEST,
-    ;
 }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/DocumentData.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/DocumentData.java
index cae039e30032..56ac3738fd4d 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/DocumentData.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/DocumentData.java
@@ -25,7 +25,7 @@
 public class DocumentData {
     //TODO: Remove this class and use DocumentConfig for creating a document
     private final String name;
-    private String content;
+    private final String content;
 
     private DocumentData(String name, String content) {
         this.name = name;
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/DotGraphs.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/DotGraphs.java
index 00418b610bbf..54a026643c04 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/DotGraphs.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/DotGraphs.java
@@ -38,7 +38,7 @@
  *
  * @since 2.0.0
  */
-public class DotGraphs {
+public final class DotGraphs {
 
     private DotGraphs() {
     }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ManifestBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ManifestBuilder.java
index 0a4a1212e722..368c9ed635b6 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ManifestBuilder.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ManifestBuilder.java
@@ -56,7 +56,6 @@
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -69,6 +68,7 @@
 
 import static io.ballerina.projects.internal.ManifestUtils.ToolNodeValueType;
 import static io.ballerina.projects.internal.ManifestUtils.convertDiagnosticToString;
+import static io.ballerina.projects.internal.ManifestUtils.getBooleanFromTomlTableNode;
 import static io.ballerina.projects.internal.ManifestUtils.getBuildToolTomlValueType;
 import static io.ballerina.projects.internal.ManifestUtils.getStringFromTomlTableNode;
 import static io.ballerina.projects.util.ProjectUtils.defaultName;
@@ -420,7 +420,7 @@ private PackageDescriptor getPackageDescriptor(TomlTableNode tomlTableNode) {
 
     private void validateIconPathForPng(String icon, TomlTableNode pkgNode) {
         if (icon != null && hasPngExtension(icon)) {
-            Path iconPath = Paths.get(icon);
+            Path iconPath = Path.of(icon);
             if (!iconPath.isAbsolute()) {
                 iconPath = this.projectPath.resolve(iconPath);
             }
@@ -552,7 +552,7 @@ private PackageManifest.Platform getDependencyPlatform(TopLevelNode dependencyNo
                         Map platformEntryMap = new HashMap<>();
                         String pathValue = getStringValueFromPlatformEntry(platformEntryTable, PATH);
                         if (pathValue != null) {
-                            Path path = Paths.get(pathValue);
+                            Path path = Path.of(pathValue);
                             if (!path.isAbsolute()) {
                                 path = this.projectPath.resolve(path);
                             }
@@ -566,6 +566,8 @@ private PackageManifest.Platform getDependencyPlatform(TopLevelNode dependencyNo
                         String artifactId = getStringValueFromPlatformEntry(platformEntryTable, ARTIFACT_ID);
                         String version = getStringValueFromPlatformEntry(platformEntryTable, VERSION);
                         String scope = getStringValueFromPlatformEntry(platformEntryTable, SCOPE);
+                        Boolean graalvmCompatibility = getBooleanValueFromPlatformEntry(platformEntryTable,
+                                GRAALVM_COMPATIBLE);
                         if (PlatformLibraryScope.PROVIDED.getStringValue().equals(scope)
                                 && !providedPlatformDependencyIsValid(artifactId, groupId, version)) {
                             reportDiagnostic(platformEntryTable,
@@ -579,6 +581,7 @@ private PackageManifest.Platform getDependencyPlatform(TopLevelNode dependencyNo
                         platformEntryMap.put(ARTIFACT_ID, artifactId);
                         platformEntryMap.put(VERSION, version);
                         platformEntryMap.put(SCOPE, scope);
+                        platformEntryMap.put(GRAALVM_COMPATIBLE, graalvmCompatibility);
                         platformEntry.add(platformEntryMap);
                     }
                 }
@@ -693,6 +696,10 @@ private BuildOptions setBuildOptions(TomlTableNode tomlTableNode) {
                 BuildOptions.OptionName.GRAAL_VM_BUILD_OPTIONS.toString());
         Boolean remoteManagement = getBooleanFromBuildOptionsTableNode(tableNode,
                 CompilerOptionName.REMOTE_MANAGEMENT.toString());
+        Boolean showDependencyDiagnostics = getBooleanFromBuildOptionsTableNode(tableNode,
+                BuildOptions.OptionName.SHOW_DEPENDENCY_DIAGNOSTICS.toString());
+        Boolean optimizeDependencyCompilation = getBooleanFromBuildOptionsTableNode(tableNode,
+                BuildOptions.OptionName.OPTIMIZE_DEPENDENCY_COMPILATION.toString());
 
         buildOptionsBuilder
                 .setOffline(offline)
@@ -707,7 +714,9 @@ private BuildOptions setBuildOptions(TomlTableNode tomlTableNode) {
                 .setNativeImage(nativeImage)
                 .setExportComponentModel(exportComponentModel)
                 .setGraalVMBuildOptions(graalVMBuildOptions)
-                .setRemoteManagement(remoteManagement);
+                .setRemoteManagement(remoteManagement)
+                .setShowDependencyDiagnostics(showDependencyDiagnostics)
+                .setOptimizeDependencyCompilation(optimizeDependencyCompilation);
 
         if (targetDir != null) {
             buildOptionsBuilder.targetDir(targetDir);
@@ -835,6 +844,14 @@ private String getStringValueFromPlatformEntry(TomlTableNode pkgNode, String key
         return getStringFromTomlTableNode(topLevelNode);
     }
 
+    private Boolean getBooleanValueFromPlatformEntry(TomlTableNode pkgNode, String key) {
+        TopLevelNode topLevelNode = pkgNode.entries().get(key);
+        if (topLevelNode == null || topLevelNode.kind() == TomlType.NONE) {
+            return null;
+        }
+        return getBooleanFromTomlTableNode(topLevelNode);
+    }
+
     private String getStringValueFromDependencyNode(TomlTableNode pkgNode, String key) {
         TopLevelNode topLevelNode = pkgNode.entries().get(key);
         if (topLevelNode == null) {
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ManifestUtils.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ManifestUtils.java
index 16b609480bf3..e72747296f28 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ManifestUtils.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ManifestUtils.java
@@ -33,7 +33,7 @@
  *
  * @since 2.0.0
  */
-public class ManifestUtils {
+public final class ManifestUtils {
 
     private ManifestUtils() {
     }
@@ -75,7 +75,7 @@ public static ToolNodeValueType getBuildToolTomlValueType(TopLevelNode topLevelN
             TomlValueNode value = keyValueNode.value();
             if (value.kind() == TomlType.STRING) {
                 TomlStringValueNode stringValueNode = (TomlStringValueNode) value;
-                if (stringValueNode.getValue().equals("")) {
+                if (stringValueNode.getValue().isEmpty()) {
                     return ToolNodeValueType.EMPTY;
                 }
                return ToolNodeValueType.STRING;
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ModuleData.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ModuleData.java
index 5ed3283535be..4829807c6ffd 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ModuleData.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ModuleData.java
@@ -33,8 +33,6 @@ public class ModuleData {
     private final List srcDocs;
     private final List testSrcDocs;
     private final DocumentData moduleMd;
-    private final List resources;
-    private final List testResources;
 
     // TODO do we need to maintain resources and test resources
 
@@ -42,26 +40,20 @@ private ModuleData(Path moduleDirPath,
                        String moduleName,
                        List srcDocs,
                        List testSrcDocs,
-                       DocumentData moduleMd,
-                       List resources,
-                       List testResources) {
+                       DocumentData moduleMd) {
         this.moduleDirPath = moduleDirPath;
         this.moduleName = moduleName;
         this.srcDocs = srcDocs;
         this.testSrcDocs = testSrcDocs;
         this.moduleMd = moduleMd;
-        this.resources = resources;
-        this.testResources = testResources;
     }
 
     public static ModuleData from(Path path,
                                   String moduleName,
                                   List srcDocuments,
                                   List testSrcDocuments,
-                                  DocumentData moduleMd,
-                                  List resources,
-                                  List testResources) {
-        return new ModuleData(path, moduleName, srcDocuments, testSrcDocuments, moduleMd, resources, testResources);
+                                  DocumentData moduleMd) {
+        return new ModuleData(path, moduleName, srcDocuments, testSrcDocuments, moduleMd);
     }
 
     public Path moduleDirectoryPath() {
@@ -92,11 +84,4 @@ public Optional moduleMd() {
         return Optional.ofNullable(this.moduleMd);
     }
 
-    public List resources () {
-        return resources;
-    }
-
-    public List testResources() {
-        return testResources;
-    }
 }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageConfigCreator.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageConfigCreator.java
index 956c726985bb..b9b527f00681 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageConfigCreator.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageConfigCreator.java
@@ -38,19 +38,25 @@
 import io.ballerina.projects.util.ProjectConstants;
 
 import java.nio.file.Path;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.stream.Collectors;
+import java.util.Set;
+import java.util.stream.Stream;
 
 /**
  * Creates a {@code PackageConfig} instance from the given {@code PackageData} instance.
  *
  * @since 2.0.0
  */
-public class PackageConfigCreator {
+public final class PackageConfigCreator {
+
+    private PackageConfigCreator() {
+    }
 
     public static PackageConfig createBuildProjectConfig(Path projectDirPath, boolean disableSyntaxTree) {
         ProjectFiles.validateBuildProjectDirPath(projectDirPath);
@@ -140,14 +146,12 @@ private static PackageConfig createPackageConfig(PackageData packageData,
         PackageName packageName = packageManifest.name();
         PackageId packageId = PackageId.create(packageName.value());
 
-        List moduleConfigs = packageData.otherModules()
-                .stream()
-                .map(moduleData -> createModuleConfig(packageManifest.descriptor(), moduleData,
-                        packageId, moduleDependencyGraph))
-                .collect(Collectors.toList());
+        List moduleConfigs = Stream.concat(packageData.otherModules().stream()
+                        .map(moduleData -> createModuleConfig(packageManifest.descriptor(), moduleData,
+                                packageId, moduleDependencyGraph)),
+                Stream.of(createDefaultModuleConfig(packageManifest.descriptor(),
+                        packageData.defaultModule(), packageId, moduleDependencyGraph))).toList();
 
-        moduleConfigs.add(createDefaultModuleConfig(packageManifest.descriptor(),
-                packageData.defaultModule(), packageId, moduleDependencyGraph));
 
         DocumentConfig ballerinaToml = packageData.ballerinaToml()
                 .map(data -> createDocumentConfig(data, null)).orElse(null);
@@ -161,11 +165,18 @@ private static PackageConfig createPackageConfig(PackageData packageData,
                 .map(data -> createDocumentConfig(data, null)).orElse(null);
         DocumentConfig packageMd = packageData.packageMd()
                 .map(data -> createDocumentConfig(data, null)).orElse(null);
-
+        List resources = new ArrayList<>();
+        List testResources = new ArrayList<>();
+        if (!packageData.resources().isEmpty()) {
+            resources = getResourceConfigs(packageData.resources(), packageData.packagePath());
+        }
+        if (!packageData.testResources().isEmpty()) {
+            testResources = getResourceConfigs(packageData.testResources(), packageData.packagePath());
+        }
         return PackageConfig
                 .from(packageId, packageData.packagePath(), packageManifest, dependencyManifest, ballerinaToml,
                         dependenciesToml, cloudToml, compilerPluginToml, balToolToml, packageMd, moduleConfigs,
-                        packageDependencyGraph, disableSyntaxTree);
+                        packageDependencyGraph, disableSyntaxTree, resources, testResources);
     }
     public static PackageConfig createPackageConfig(PackageData packageData,
                                                     PackageManifest packageManifest,
@@ -220,23 +231,19 @@ private static ModuleConfig createModuleConfig(ModuleDescriptor moduleDescriptor
         DocumentConfig moduleMd = moduleData.moduleMd()
                 .map(data -> createDocumentConfig(data, null)).orElse(null);
 
-        List resources = getResourceConfigs(
-                moduleId, moduleData.resources(), moduleData.moduleDirectoryPath());
-        List testResources = getResourceConfigs(
-                moduleId, moduleData.testResources(), moduleData.moduleDirectoryPath()
-                        .resolve(ProjectConstants.TEST_DIR_NAME));
-        return ModuleConfig.from(moduleId, moduleDescriptor, srcDocs, testSrcDocs, moduleMd, dependencies, resources,
-                testResources);
+        return ModuleConfig.from(moduleId, moduleDescriptor, srcDocs, testSrcDocs, moduleMd, dependencies);
     }
 
-    private static List getResourceConfigs(ModuleId moduleId, List resources, Path modulePath) {
-        return resources.stream().map(resource ->
-                createResourceConfig(resource, modulePath, moduleId)).collect(Collectors.toList());
+    private static List getResourceConfigs(List resources, Path packagePath) {
+        // TODO: no need Remove duplicate paths before processing
+        Set distinctResources = new HashSet<>(resources);
+        return distinctResources.stream().map(
+                distinctResource -> createResourceConfig(distinctResource, packagePath)).toList();
     }
 
-    private static ResourceConfig createResourceConfig(Path path, Path modulePath, ModuleId moduleId) {
-        final DocumentId documentId = DocumentId.create(path.toString(), moduleId);
-        return ProvidedResourceConfig.from(documentId, path, modulePath);
+    private static ResourceConfig createResourceConfig(Path path, Path packagePath) {
+        final DocumentId documentId = DocumentId.create(path.toString(), null);
+        return ProvidedResourceConfig.from(documentId, path, packagePath);
     }
 
     private static List getDocumentConfigs(ModuleId moduleId, List documentData) {
@@ -244,7 +251,7 @@ private static List getDocumentConfigs(ModuleId moduleId, List createDocumentConfig(srcDoc, moduleId))
-                .collect(Collectors.toList());
+                .toList();
     }
 
     static DocumentConfig createDocumentConfig(DocumentData documentData, ModuleId moduleId) {
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageContainer.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageContainer.java
index 388e70059a10..253f4189a3ec 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageContainer.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageContainer.java
@@ -25,7 +25,6 @@
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Optional;
-import java.util.stream.Collectors;
 
 /**
  * A container for various package representation that provides efficient access to packages.
@@ -81,6 +80,6 @@ public Collection getAll() {
                 .stream()
                 .map(Map::values)
                 .flatMap(Collection::stream)
-                .collect(Collectors.toList());
+                .toList();
     }
 }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageData.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageData.java
index 30ba2d1361bd..fd8be26e51de 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageData.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageData.java
@@ -43,7 +43,8 @@ public class PackageData {
     private final DocumentData compilerPluginToml;
     private final DocumentData balToolToml;
     private final DocumentData packageMd;
-
+    private final List resources;
+    private final List testResources;
 
     private PackageData(Path packagePath,
                         ModuleData defaultModule,
@@ -55,7 +56,9 @@ private PackageData(Path packagePath,
                         DocumentData cloudToml,
                         DocumentData compilerPluginToml,
                         DocumentData balToolToml,
-                        DocumentData packageMd) {
+                        DocumentData packageMd,
+                        List resources,
+                        List testResources) {
         this.packagePath = packagePath;
         this.defaultModule = defaultModule;
         this.otherModules = otherModules;
@@ -67,6 +70,8 @@ private PackageData(Path packagePath,
         this.cloudToml = cloudToml;
         this.compilerPluginToml = compilerPluginToml;
         this.balToolToml = balToolToml;
+        this.resources = resources;
+        this.testResources = testResources;
     }
 
     public static PackageData from(Path packagePath,
@@ -77,10 +82,12 @@ public static PackageData from(Path packagePath,
                                    DocumentData cloudToml,
                                    DocumentData compilerPluginToml,
                                    DocumentData balToolToml,
-                                   DocumentData packageMd) {
+                                   DocumentData packageMd,
+                                   List resources,
+                                   List testResources) {
         return new PackageData(packagePath, defaultModule, otherModules, DependencyGraph.emptyGraph(),
                                DependencyGraph.emptyGraph(), ballerinaToml, dependenciesToml, cloudToml,
-                               compilerPluginToml, balToolToml, packageMd);
+                               compilerPluginToml, balToolToml, packageMd, resources, testResources);
     }
 
     public static PackageData from(Path packagePath,
@@ -93,10 +100,12 @@ public static PackageData from(Path packagePath,
                                    DocumentData cloudToml,
                                    DocumentData compilerPluginToml,
                                    DocumentData balToolToml,
-                                   DocumentData packageMd) {
+                                   DocumentData packageMd,
+                                   List resources,
+                                   List testResources) {
         return new PackageData(packagePath, defaultModule, otherModules, packageDesDependencyGraph,
                 moduleDependencyGraph, ballerinaToml, dependenciesToml, cloudToml, compilerPluginToml,
-                balToolToml, packageMd);
+                balToolToml, packageMd, resources, testResources);
     }
 
     public Path packagePath() {
@@ -142,4 +151,12 @@ public Optional balToolToml() {
     public Optional packageMd() {
         return Optional.ofNullable(packageMd);
     }
+
+    public List resources () {
+        return resources;
+    }
+
+    public List testResources() {
+        return testResources;
+    }
 }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageDependencyGraphBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageDependencyGraphBuilder.java
index ca46468fc549..5677f676cbe9 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageDependencyGraphBuilder.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageDependencyGraphBuilder.java
@@ -43,7 +43,6 @@
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
-import java.util.stream.Collectors;
 
 /**
  * This class is responsible for creating the Package dependency graph with no version conflicts.
@@ -145,7 +144,7 @@ public boolean containsNode(PackageDescriptor node) {
     public Collection getAllDependencies() {
         return vertices.values().stream()
                 .filter(vertex -> !vertex.equals(rootDepNode))
-                .collect(Collectors.toList());
+                .toList();
     }
 
     public DependencyGraph buildGraph() {
@@ -176,7 +175,7 @@ public DependencyGraph buildGraph() {
     public Collection getUnresolvedNodes() {
         Collection unresolvedNodes = unresolvedVertices.stream()
                 .map(vertices::get)
-                .collect(Collectors.toList());
+                .toList();
         this.unresolvedVertices = new HashSet<>();
         return unresolvedNodes;
     }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageDiagnostic.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageDiagnostic.java
index ec1502a9bb37..a28fac53fd67 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageDiagnostic.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageDiagnostic.java
@@ -34,7 +34,6 @@
 import java.io.File;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.List;
 import java.util.Optional;
 
@@ -65,13 +64,13 @@ public PackageDiagnostic(Diagnostic diagnostic, ModuleDescriptor moduleDescripto
         String filePath;
         ModuleName moduleName = moduleDescriptor.name();
         String diagnosticPath = diagnostic.location().lineRange().filePath();
-        Path modulesRoot = Paths.get(ProjectConstants.MODULES_ROOT);
+        Path modulesRoot = Path.of(ProjectConstants.MODULES_ROOT);
         if (project.kind().equals(ProjectKind.BALA_PROJECT)) {
             Path modulePath = modulesRoot.resolve(moduleName.toString());
             filePath = project.sourceRoot().resolve(modulePath).resolve(
                     diagnosticPath).toString();
         } else {
-            Path generatedRoot = Paths.get(ProjectConstants.GENERATED_MODULES_ROOT);
+            Path generatedRoot = Path.of(ProjectConstants.GENERATED_MODULES_ROOT);
             if (!moduleName.isDefaultModuleName()) {
                 Path generatedPath = generatedRoot.
                         resolve(moduleName.moduleNamePart());
@@ -122,7 +121,7 @@ public String toString() {
         if (this.project != null && ProjectKind.BALA_PROJECT.equals(this.project.kind())) {
             filePath = moduleDescriptor.org() + "/" +
                     moduleDescriptor.name().toString() + "/" +
-                    moduleDescriptor.version() + "::" + Optional.of(Paths.get(filePath).getFileName()).get();
+                    moduleDescriptor.version() + "::" + Optional.of(Path.of(filePath).getFileName()).get();
         }
         // Handle null location based diagnostics
         if (this.diagnostic.location() instanceof NullLocation) {
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageVersionContainer.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageVersionContainer.java
index 1078e6318708..b7f26b6b79b3 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageVersionContainer.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/PackageVersionContainer.java
@@ -26,7 +26,6 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Optional;
-import java.util.stream.Collectors;
 
 /**
  * A container for various package representation that provides efficient access to packages.
@@ -82,6 +81,6 @@ public Collection getAll() {
                 .flatMap(Collection::stream)
                 .map(Map::values)
                 .flatMap(Collection::stream)
-                .collect(Collectors.toList());
+                .toList();
     }
 }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ProjectDiagnosticErrorCode.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ProjectDiagnosticErrorCode.java
index 5c6523baa540..63d6483cf6a9 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ProjectDiagnosticErrorCode.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ProjectDiagnosticErrorCode.java
@@ -61,6 +61,9 @@ public enum ProjectDiagnosticErrorCode implements DiagnosticCode {
     // Error codes used for Jar resolving.
     CONFLICTING_PLATFORM_JAR_FILES("BCE5501", "conflicting.platform.jars.type"),
     PROVIDED_PLATFORM_JAR_IN_EXECUTABLE("BCE5502", "provided.platform.jars"),
+
+    // Error codes used in resources resolution
+    CONFLICTING_RESOURCE_FILE("BCE5601", "conflicting.resources.type")
     ;
 
     private final String diagnosticId;
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ProjectFiles.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ProjectFiles.java
index 7f6c4506fbaf..b76b2fdcb02d 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ProjectFiles.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ProjectFiles.java
@@ -28,6 +28,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.io.PrintStream;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.FileSystems;
@@ -42,6 +43,8 @@
 import java.util.stream.Stream;
 
 import static io.ballerina.projects.util.ProjectConstants.DOT;
+import static io.ballerina.projects.util.ProjectConstants.GENERATED_MODULES_ROOT;
+import static io.ballerina.projects.util.ProjectConstants.RESOURCE_DIR_NAME;
 import static io.ballerina.projects.util.ProjectConstants.TEST_DIR_NAME;
 import static io.ballerina.projects.util.ProjectUtils.checkReadPermission;
 
@@ -50,11 +53,13 @@
  *
  * @since 2.0.0
  */
-public class ProjectFiles {
+public final class ProjectFiles {
+
     public static final PathMatcher BAL_EXTENSION_MATCHER =
             FileSystems.getDefault().getPathMatcher("glob:**.bal");
     public static final PathMatcher BALA_EXTENSION_MATCHER =
             FileSystems.getDefault().getPathMatcher("glob:**.bala");
+    private static final PrintStream outStream = System.out;
 
     private ProjectFiles() {
     }
@@ -62,30 +67,39 @@ private ProjectFiles() {
     public static PackageData loadSingleFileProjectPackageData(Path filePath) {
         DocumentData documentData = loadDocument(filePath);
         ModuleData defaultModule = ModuleData
-                .from(filePath, DOT, Collections.singletonList(documentData), Collections.emptyList(), null,
-                        Collections.emptyList(), Collections.emptyList());
+                .from(filePath, DOT, Collections.singletonList(documentData), Collections.emptyList(), null);
         return PackageData.from(filePath, defaultModule, Collections.emptyList(),
-                null, null, null, null, null, null);
+                null, null, null, null,
+                null, null, Collections.emptyList(), Collections.emptyList());
     }
 
     public static PackageData loadBuildProjectPackageData(Path packageDirPath) {
         ModuleData defaultModule = loadModule(packageDirPath);
         List otherModules = loadOtherModules(packageDirPath);
         List newModules = loadNewGeneratedModules(packageDirPath);
-        if (otherModules.isEmpty()) {
-            otherModules = newModules;
-        } else {
-            otherModules.addAll(newModules);
-        }
+        otherModules = Stream.concat(otherModules.stream(), newModules.stream()).toList();
+
         DocumentData ballerinaToml = loadDocument(packageDirPath.resolve(ProjectConstants.BALLERINA_TOML));
         DocumentData dependenciesToml = loadDocument(packageDirPath.resolve(ProjectConstants.DEPENDENCIES_TOML));
         DocumentData cloudToml = loadDocument(packageDirPath.resolve(ProjectConstants.CLOUD_TOML));
         DocumentData compilerPluginToml = loadDocument(packageDirPath.resolve(ProjectConstants.COMPILER_PLUGIN_TOML));
         DocumentData balToolToml = loadDocument(packageDirPath.resolve(ProjectConstants.BAL_TOOL_TOML));
         DocumentData packageMd = loadDocument(packageDirPath.resolve(ProjectConstants.PACKAGE_MD_FILE_NAME));
-
+        List resources = loadResources(packageDirPath);
+        // load generated resources
+        List generatedResources = loadResources(packageDirPath.resolve(GENERATED_MODULES_ROOT));
+        if (!generatedResources.isEmpty()) {
+            resources.addAll(generatedResources);
+        }
+        List testResources = loadResources(packageDirPath.resolve(ProjectConstants.TEST_DIR_NAME));
+        // load generated test resources
+        List generatedTestResources = loadResources(packageDirPath.resolve(
+                GENERATED_MODULES_ROOT).resolve(TEST_DIR_NAME));
+        if (!generatedTestResources.isEmpty()) {
+            testResources.addAll(generatedTestResources);
+        }
         return PackageData.from(packageDirPath, defaultModule, otherModules, ballerinaToml, dependenciesToml,
-                cloudToml, compilerPluginToml, balToolToml, packageMd);
+                cloudToml, compilerPluginToml, balToolToml, packageMd, resources, testResources);
     }
 
     private static List loadNewGeneratedModules(Path packageDirPath) {
@@ -109,7 +123,7 @@ private static List loadNewGeneratedModules(Path packageDirPath) {
                             return true;
                         })
                         .map(ProjectFiles::loadModule)
-                        .collect(Collectors.toList());
+                        .toList();
             } catch (IOException e) {
                 throw new ProjectException(e);
             }
@@ -119,7 +133,7 @@ private static List loadNewGeneratedModules(Path packageDirPath) {
 
     private static boolean isNewModule(Path packageDirPath, Path path) {
         String dirName = path.toFile().getName();
-        if (dirName.equals(TEST_DIR_NAME)) {
+        if (dirName.equals(TEST_DIR_NAME) || dirName.equals(RESOURCE_DIR_NAME)) {
             return false;
         }
         Path modulePath = packageDirPath.resolve(ProjectConstants.MODULES_ROOT).resolve(dirName);
@@ -157,22 +171,15 @@ private static List loadOtherModules(Path packageDirPath) {
 
     private static ModuleData loadModule(Path moduleDirPath) {
         List srcDocs = loadDocuments(moduleDirPath);
-        List testSrcDocs;
         Path testDirPath = moduleDirPath.resolve("tests");
-        testSrcDocs = Files.isDirectory(testDirPath) ? loadTestDocuments(testDirPath) : new ArrayList<>();
+        List testSrcDocs = Files.isDirectory(testDirPath) ? loadTestDocuments(testDirPath) :
+                new ArrayList<>();
 
         // If the module is not a newly generated module, explicitly load generated sources
         if (!ProjectConstants.GENERATED_MODULES_ROOT.equals(Optional.of(
                 moduleDirPath.toAbsolutePath().getParent()).get().toFile().getName())) {
-            // Generated sources root for default module
-            Path generatedSourcesRoot = moduleDirPath.resolve(ProjectConstants.GENERATED_MODULES_ROOT);
-            if (ProjectConstants.MODULES_ROOT.equals(Optional.of(
-                    moduleDirPath.toAbsolutePath().getParent()).get().toFile().getName())) {
-                // generated sources root for non-default modules
-                generatedSourcesRoot = Optional.of(Optional.of(Optional.of(moduleDirPath.toAbsolutePath().getParent()).
-                                        get().getParent()).get().resolve(ProjectConstants.GENERATED_MODULES_ROOT))
-                        .get().resolve(Optional.of(moduleDirPath.toFile()).get().getName());
-            }
+            // Generated source root for default module
+            Path generatedSourcesRoot = getGeneratedSourcesRoot(moduleDirPath);
             if (Files.isDirectory(generatedSourcesRoot)) {
                 List generatedDocs = loadDocuments(generatedSourcesRoot);
                 verifyDuplicateNames(srcDocs, generatedDocs, moduleDirPath.toFile().getName(), moduleDirPath, false);
@@ -187,11 +194,36 @@ private static ModuleData loadModule(Path moduleDirPath) {
             }
         }
         DocumentData moduleMd = loadDocument(moduleDirPath.resolve(ProjectConstants.MODULE_MD_FILE_NAME));
-        List resources = loadResources(moduleDirPath);
-        List testResources = loadResources(moduleDirPath.resolve(ProjectConstants.TEST_DIR_NAME));
+
+        // Warn if there are module level resources
+        Path parentPath = moduleDirPath.getParent();
+        if (parentPath != null && ProjectConstants.MODULES_ROOT.equals(
+                parentPath.toFile().getName())) {
+            List moduleResources = loadResources(moduleDirPath);
+            if (!moduleResources.isEmpty()) {
+                String diagnosticMsg = "WARNING: module-level resources are not supported. Relocate the module-level " +
+                        "resources detected in '" + moduleDirPath.toFile().getName() + "' to the package " +
+                        "resources path. Resource files:\n" +
+                        moduleResources.stream()
+                                .map(Path::toString)
+                                .collect(Collectors.joining("\n")) + "\n";
+                ProjectUtils.addProjectLoadingDiagnostic(diagnosticMsg);
+            }
+        }
         // TODO Read Module.md file. Do we need to? Bala creator may need to package Module.md
-        return ModuleData.from(moduleDirPath, moduleDirPath.toFile().getName(), srcDocs, testSrcDocs, moduleMd,
-                resources, testResources);
+        return ModuleData.from(moduleDirPath, moduleDirPath.toFile().getName(), srcDocs, testSrcDocs, moduleMd);
+    }
+
+    private static Path getGeneratedSourcesRoot(Path moduleDirPath) {
+        Path generatedSourcesRoot = moduleDirPath.resolve(ProjectConstants.GENERATED_MODULES_ROOT);
+        if (ProjectConstants.MODULES_ROOT.equals(Optional.of(
+                moduleDirPath.toAbsolutePath().getParent()).get().toFile().getName())) {
+            // generated sources root for non-default modules
+            generatedSourcesRoot = Optional.of(Optional.of(Optional.of(moduleDirPath.toAbsolutePath().getParent()).
+                                    get().getParent()).get().resolve(ProjectConstants.GENERATED_MODULES_ROOT))
+                    .get().resolve(Optional.of(moduleDirPath.toFile()).get().getName());
+        }
+        return generatedSourcesRoot;
     }
 
     private static void verifyDuplicateNames(List srcDocs, List generatedDocs,
@@ -213,21 +245,20 @@ private static void verifyDuplicateNames(List srcDocs, List loadResources(Path modulePath) {
-        Path resourcesPath = modulePath.resolve(ProjectConstants.RESOURCE_DIR_NAME);
+    public static List loadResources(Path packagePath) {
+        Path resourcesPath = packagePath.resolve(ProjectConstants.RESOURCE_DIR_NAME);
         if (Files.notExists(resourcesPath)) {
             return Collections.emptyList();
         }
-
         try {
-            checkReadPermission(modulePath);
+            checkReadPermission(packagePath);
         } catch (UnsupportedOperationException ignore) {
             // ignore for zip entries
         }
         try (Stream pathStream = Files.walk(resourcesPath, 10)) {
             return pathStream
                     .filter(Files::isRegularFile)
-                    .collect(Collectors.toList());
+                    .toList();
         } catch (IOException e) {
             throw new ProjectException(e);
         }
@@ -334,7 +365,7 @@ public static void validateBuildProjectDirPath(Path projectDirPath) {
         }
 
         if (ProjectUtils.findProjectRoot(projectDirPath.toAbsolutePath().getParent()) != null) {
-            throw new ProjectException("Provided path is already within a Ballerina package: " + projectDirPath);
+            throw new ProjectException("'" + projectDirPath + "' is already within a Ballerina package");
         }
 
         checkReadPermission(projectDirPath);
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ProvidedResourceConfig.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ProvidedResourceConfig.java
index 2fcd4817be4b..bf499d3df630 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ProvidedResourceConfig.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ProvidedResourceConfig.java
@@ -21,9 +21,9 @@
 import io.ballerina.projects.DocumentId;
 import io.ballerina.projects.ResourceConfig;
 import io.ballerina.projects.util.ProjectConstants;
-import org.apache.commons.io.FilenameUtils;
 
 import java.nio.file.Path;
+import java.util.Locale;
 
 /**
  * {@code Resource} contains necessary configuration elements required to create an instance of a {@code Resource}.
@@ -37,13 +37,33 @@
  */
 public class ProvidedResourceConfig extends ResourceConfig {
 
+    public static final String OS = System.getProperty("os.name").toLowerCase(Locale.getDefault());
+
     private ProvidedResourceConfig(DocumentId documentId, Path path, String name, byte[] content) {
         super(documentId, path, name, content);
     }
 
-    public static ProvidedResourceConfig from(DocumentId documentId, Path resource, Path modulePath) {
-        Path resourcePath = modulePath.resolve(ProjectConstants.RESOURCE_DIR_NAME).relativize(resource);
-        String unixPath = FilenameUtils.separatorsToUnix(resourcePath.toString());
-        return new ProvidedResourceConfig(documentId, resource, unixPath, null);
+    public static ProvidedResourceConfig from(DocumentId documentId, Path resource, Path packagePath) {
+        Path relativeResourcePath;
+        if (resource.startsWith(packagePath)) {
+            relativeResourcePath = packagePath.relativize(resource);
+        } else {
+            relativeResourcePath = resource;
+        }
+        String resourcePath = relativeResourcePath.toString();
+        String marker = ProjectConstants.RESOURCE_DIR_NAME + (OS.contains("win") ? "\\" : "/");
+        int markerIndex = resourcePath.indexOf(marker);
+        String path = markerIndex != -1
+                ? resourcePath.substring(markerIndex + marker.length())
+                : resourcePath;
+        return new ProvidedResourceConfig(documentId, resource, convertWinPathToUnixFormat(path), null);
+    }
+
+    public static String convertWinPathToUnixFormat(String path) {
+        if (OS.contains("win")) {
+            path = path.replace("\\", "/");
+        }
+        return path;
     }
+
 }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ResolutionEngine.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ResolutionEngine.java
index b12f63e498b8..73713023da59 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ResolutionEngine.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/ResolutionEngine.java
@@ -45,7 +45,6 @@
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
-import java.util.stream.Collectors;
 
 /**
  * Responsible for creating the dependency graph with automatic version updates.
@@ -163,7 +162,7 @@ private Collection resolvePackages(Collection
 
     private void populateStaticDependencyGraph(Collection directDependencies) {
         List errorNodes = directDependencies.stream()
-                .filter(DependencyNode::errorNode).collect(Collectors.toList());
+                .filter(DependencyNode::errorNode).toList();
         for (DependencyNode errorNode : errorNodes) {
             graphBuilder.addErroneousDependency(
                     rootPkgDesc, errorNode.pkgDesc, errorNode.scope, errorNode.resolutionType);
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/SettingsBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/SettingsBuilder.java
index b399be860c95..fefc484a176a 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/SettingsBuilder.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/SettingsBuilder.java
@@ -55,10 +55,11 @@ public class SettingsBuilder {
     private static final String READ_TIMEOUT = "readTimeout";
     private static final String WRITE_TIMEOUT = "writeTimeout";
     private static final String CALL_TIMEOUT = "callTimeout";
-    private TomlDocument settingsToml;
-    private Settings settings;
+    private static final String MAX_RETRIES = "maxRetries";
+    private final TomlDocument settingsToml;
+    private final Settings settings;
     private DiagnosticResult diagnostics;
-    private List diagnosticList;
+    private final List diagnosticList;
 
     private static final String PROXY = "proxy";
     private static final String CENTRAL = "central";
@@ -74,6 +75,7 @@ public class SettingsBuilder {
     private static final int DEFAULT_READ_TIMEOUT = 60;
     private static final int DEFAULT_WRITE_TIMEOUT = 60;
     private static final int DEFAULT_CALL_TIMEOUT = 0;
+    public static final int DEFAULT_MAX_RETRY = 1;
 
     private SettingsBuilder(TomlDocument settingsToml) {
         this.diagnosticList = new ArrayList<>();
@@ -123,6 +125,7 @@ private Settings parseAsSettings() {
         int readTimeout = DEFAULT_READ_TIMEOUT;
         int writeTimeout = DEFAULT_WRITE_TIMEOUT;
         int callTimeout = DEFAULT_CALL_TIMEOUT;
+        int maxRetries = DEFAULT_MAX_RETRY;
         String url = "";
         String id = "";
         String repoName = "";
@@ -146,6 +149,10 @@ private Settings parseAsSettings() {
                 readTimeout = getIntValueFromProxyNode(centralNode, READ_TIMEOUT, DEFAULT_READ_TIMEOUT);
                 writeTimeout = getIntValueFromProxyNode(centralNode, WRITE_TIMEOUT, DEFAULT_WRITE_TIMEOUT);
                 callTimeout = getIntValueFromProxyNode(centralNode, CALL_TIMEOUT, DEFAULT_CALL_TIMEOUT);
+                maxRetries = getIntValueFromProxyNode(centralNode, MAX_RETRIES, DEFAULT_MAX_RETRY);
+                if (maxRetries < 0) {
+                    maxRetries = DEFAULT_MAX_RETRY;
+                }
             }
 
             TomlTableNode repository = (TomlTableNode) tomlAstNode.entries().get(REPOSITORY);
@@ -170,7 +177,7 @@ private Settings parseAsSettings() {
         }
 
         return Settings.from(Proxy.from(host, port, proxyUsername, proxyPassword), Central.from(accessToken,
-                connectTimeout, readTimeout, writeTimeout, callTimeout), diagnostics(),
+                connectTimeout, readTimeout, writeTimeout, callTimeout, maxRetries), diagnostics(),
                 repositories.toArray(new Repository[0]));
     }
 
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/TransactionImportValidator.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/TransactionImportValidator.java
index 3848bd8b0d0c..89471c9ade04 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/TransactionImportValidator.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/TransactionImportValidator.java
@@ -31,7 +31,6 @@
 import io.ballerina.compiler.syntax.tree.TransactionalExpressionNode;
 
 import java.util.List;
-import java.util.stream.Collectors;
 
 /**
  * This class will check whether an import statement to internal transaction repo is needed or not.
@@ -72,7 +71,7 @@ public void visit(RetryStatementNode retryStatementNode) {
     @Override
     public void visit(FunctionDefinitionNode functionDefinitionNode) {
         List qualifiers = functionDefinitionNode.qualifierList().stream().map(Token::text)
-                .collect(Collectors.toList());
+                .toList();
         if (qualifiers.contains(SyntaxKind.TRANSACTIONAL_KEYWORD.stringValue()) &&
                 qualifiers.contains(SyntaxKind.RESOURCE_KEYWORD.stringValue())) {
             importTransactionPackage = true;
@@ -85,6 +84,7 @@ public void visit(TransactionalExpressionNode transactionalExpressionNode) {
         importTransactionPackage = true;
     }
 
+    @Override
     protected void visitSyntaxNode(Node node) {
         if (importTransactionPackage) {
             return;
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/bala/BalToolJson.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/bala/BalToolJson.java
index d4c390990779..0f41d6a82284 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/bala/BalToolJson.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/bala/BalToolJson.java
@@ -25,7 +25,7 @@
  * @since 2201.6.0
  */
 public class BalToolJson {
-    private String tool_id;
+    private final String tool_id;
     private List dependency_paths;
 
     public BalToolJson(String tool_id, List dependency_paths) {
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/bala/CompilerPluginJson.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/bala/CompilerPluginJson.java
index 319492615782..385373403c32 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/bala/CompilerPluginJson.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/bala/CompilerPluginJson.java
@@ -25,8 +25,8 @@
  * @since 2.0.0
  */
 public class CompilerPluginJson {
-    private String plugin_id;
-    private String plugin_class;
+    private final String plugin_id;
+    private final String plugin_class;
     private List dependency_paths;
 
     public CompilerPluginJson(String pluginId, String pluginClass, List dependencyPaths) {
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/configschema/ConfigSchemaBuilder.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/configschema/ConfigSchemaBuilder.java
index f3ddba9a6b10..dcd4ae2ae3db 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/configschema/ConfigSchemaBuilder.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/configschema/ConfigSchemaBuilder.java
@@ -147,9 +147,11 @@ private static JsonArray getRequiredConfigs(List configVariables
     private JsonObject setConfigVariables(List configVariables,
                                                  JsonObject node) {
         for (ConfigVariable configVariable : configVariables) {
-            JsonObject typeNode = new TypeConverter().getType(configVariable.type());
-            typeNode.addProperty("description", configVariable.description());
-            node.add(configVariable.name(), typeNode);
+            if (configVariable.type() != null) {
+                JsonObject typeNode = new TypeConverter().getType(configVariable.type());
+                typeNode.addProperty("description", configVariable.description());
+                node.add(configVariable.name(), typeNode);
+            }
         }
         return node;
     }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/configschema/TypeConverter.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/configschema/TypeConverter.java
index ad128e640726..17cdd218c171 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/configschema/TypeConverter.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/configschema/TypeConverter.java
@@ -58,7 +58,7 @@ public class TypeConverter {
     static final String ADDITIONAL_PROPERTIES = "additionalProperties";
     static final String TYPE = "type";
     // Stores already visited complex types against the type name
-    private Map visitedTypeMap = new HashMap<>();
+    private final Map visitedTypeMap = new HashMap<>();
 
     private VisitedType getVisitedType(String typeName) {
         if (visitedTypeMap.containsKey(typeName)) {
@@ -90,7 +90,7 @@ JsonObject getType(BType type) {
             String typeVal = getSimpleType(type);
             typeNode.addProperty(TYPE, typeVal);
         } else {
-            if (TypeTags.INTERSECTION == type.tag && type instanceof BIntersectionType) {
+            if (TypeTags.INTERSECTION == type.tag && type instanceof BIntersectionType intersectionType) {
                 BType effectiveType = Types.getImpliedType(type);
                 if (TypeTags.isSimpleBasicType(effectiveType.tag)) {
                     String typeVal = getSimpleType(effectiveType);
@@ -111,31 +111,31 @@ JsonObject getType(BType type) {
                     visitedTypeMap.put(effectiveType.toString(), new VisitedType());
                 }
 
-                if (TypeTags.ARRAY == effectiveType.tag && effectiveType instanceof BArrayType) {
-                    generateArrayType(typeNode, (BArrayType) effectiveType);
+                if (TypeTags.ARRAY == effectiveType.tag && effectiveType instanceof BArrayType arrayType) {
+                    generateArrayType(typeNode, arrayType);
                 }
-                if (TypeTags.RECORD == effectiveType.tag && effectiveType instanceof BRecordType) {
-                    typeNode = generateRecordType((BRecordType) effectiveType, (BIntersectionType) type);
+                if (TypeTags.RECORD == effectiveType.tag && effectiveType instanceof BRecordType recordType) {
+                    typeNode = generateRecordType(recordType, intersectionType);
                 }
-                if (TypeTags.MAP == effectiveType.tag && effectiveType instanceof BMapType) {
-                    generateMapType(typeNode, (BMapType) effectiveType);
+                if (TypeTags.MAP == effectiveType.tag && effectiveType instanceof BMapType mapType) {
+                    generateMapType(typeNode, mapType);
                 }
-                if (TypeTags.UNION == effectiveType.tag && effectiveType instanceof BUnionType) {
-                    generateUnionType(typeNode, (BUnionType) effectiveType);
+                if (TypeTags.UNION == effectiveType.tag && effectiveType instanceof BUnionType unionType) {
+                    generateUnionType(typeNode, unionType);
                 }
-                if (TypeTags.TABLE == effectiveType.tag && effectiveType instanceof BTableType) {
-                    generateTableType(typeNode, (BTableType) effectiveType);
+                if (TypeTags.TABLE == effectiveType.tag && effectiveType instanceof BTableType tableType) {
+                    generateTableType(typeNode, tableType);
                 }
                 completeVisitedTypeEntry(effectiveType.toString(), typeNode);
-            } else if (TypeTags.UNION == type.tag && type instanceof BUnionType) {
+            } else if (TypeTags.UNION == type.tag && type instanceof BUnionType unionType) {
                 // Handles enums
-                generateUnionType(typeNode, (BUnionType) type);
+                generateUnionType(typeNode, unionType);
             }
             // When the type is a union of singletons
-            if (TypeTags.FINITE == type.tag && type instanceof BFiniteType) {
+            if (TypeTags.FINITE == type.tag && type instanceof BFiniteType finiteType) {
                 JsonArray enumArray = new JsonArray();
                 // Singletons can be mapped to enum in JSON
-                getEnumArray(enumArray, (BFiniteType) type);
+                getEnumArray(enumArray, finiteType);
                 typeNode.add("enum", enumArray);
             }
         }
@@ -248,13 +248,13 @@ private void updateUnionMembers(LinkedHashSet members, JsonArray memberAr
                     (TypeTags.INTERSECTION == member.tag && member instanceof BIntersectionType)) {
                 JsonObject memberObj = getType(member);
                 memberArray.add(memberObj);
-            } else if (TypeTags.FINITE == member.tag && member instanceof BFiniteType) {
-                getEnumArray(enumArray, (BFiniteType) member);
-            } else if (TypeTags.TYPEREFDESC == member.tag && member instanceof BTypeReferenceType) {
+            } else if (TypeTags.FINITE == member.tag && member instanceof BFiniteType finiteType) {
+                getEnumArray(enumArray, finiteType);
+            } else if (TypeTags.TYPEREFDESC == member.tag && member instanceof BTypeReferenceType typeReferenceType) {
                 // When union member refers to another union type, update those union members as well
-                BType referredType = ((BTypeReferenceType) member).referredType;
-                if (TypeTags.UNION == referredType.tag && referredType instanceof BUnionType) {
-                    LinkedHashSet subMembers = ((BUnionType) referredType).getMemberTypes();
+                BType referredType = typeReferenceType.referredType;
+                if (TypeTags.UNION == referredType.tag && referredType instanceof BUnionType unionType) {
+                    LinkedHashSet subMembers = unionType.getMemberTypes();
                     updateUnionMembers(subMembers, memberArray, enumArray);
                 }
             }
@@ -270,21 +270,21 @@ private void updateUnionMembers(LinkedHashSet members, JsonArray memberAr
     private static void getEnumArray(JsonArray enumArray, BFiniteType finiteType) {
         Object[] values = finiteType.getValueSpace().toArray();
         for (Object finiteValue : values) {
-            if (finiteValue instanceof BLangNumericLiteral) {
-                BType bType = ((BLangNumericLiteral) finiteValue).getBType();
+            if (finiteValue instanceof BLangNumericLiteral numericLiteral) {
+                BType bType = numericLiteral.getBType();
                 // In the BLangNumericLiteral the integer typed values are represented as numeric values
                 // while the decimal values are represented as String
-                Object value = ((BLangNumericLiteral) finiteValue).getValue();
+                Object value = numericLiteral.getValue();
                 if (TypeTags.isIntegerTypeTag(bType.tag)) {
                     // Any integer can be considered as a long and added as a numeric value to the enum array
-                    if (value instanceof Long) {
-                        enumArray.add((Long) value);
+                    if (value instanceof Long l) {
+                        enumArray.add(l);
                     }
                 } else {
                     enumArray.add(Double.parseDouble(value.toString()));
                 }
-            } else if (finiteValue instanceof BLangLiteral) {
-                enumArray.add(((BLangLiteral) finiteValue).getValue().toString());
+            } else if (finiteValue instanceof BLangLiteral bLangLiteral) {
+                enumArray.add(bLangLiteral.getValue().toString());
             }
         }
     }
@@ -301,17 +301,12 @@ private static String getSimpleType(BType type) {
         } else if (TypeTags.isStringTypeTag(type.tag)) {
             return "string";
         } else {
-            switch (type.tag) {
-                case FLOAT:
-                case DECIMAL:
-                    return "number";
-                case BOOLEAN:
-                    return "boolean";
-                case BYTE:
-                    return "integer";
-                default:
-                    return "";
-            }
+            return switch (type.tag) {
+                case FLOAT, DECIMAL -> "number";
+                case BOOLEAN -> "boolean";
+                case BYTE -> "integer";
+                default -> "";
+            };
         }
     }
 
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/BallerinaDistribution.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/BallerinaDistribution.java
index 25e84ec84e9c..7da5c7c53e65 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/BallerinaDistribution.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/BallerinaDistribution.java
@@ -26,7 +26,6 @@
 
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 
 /**
  * Represents the Ballerina distribution and responsible for initializing the {@code CompilerContext}, distribution
@@ -51,7 +50,7 @@ public static BallerinaDistribution from(Environment environment) {
         if (ballerinaHome == null) {
             throw new IllegalStateException("ballerina.home property is not set");
         }
-        return from(environment, Paths.get(ballerinaHome));
+        return from(environment, Path.of(ballerinaHome));
     }
 
     public static BallerinaDistribution from(Environment environment, Path ballerinaHomeDirPath) {
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/BallerinaUserHome.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/BallerinaUserHome.java
index 904b0392b524..c2d2432b6c1e 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/BallerinaUserHome.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/BallerinaUserHome.java
@@ -17,7 +17,6 @@
 import java.nio.file.AccessDeniedException;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -86,7 +85,7 @@ public static BallerinaUserHome from(Environment environment) {
             throw new ProjectException("unable to get user home directory");
         }
 
-        Path homeRepoPath = Paths.get(userHomeDir, ProjectConstants.HOME_REPO_DEFAULT_DIRNAME);
+        Path homeRepoPath = Path.of(userHomeDir, ProjectConstants.HOME_REPO_DEFAULT_DIRNAME);
         return from(environment, homeRepoPath);
     }
 
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/DefaultEnvironment.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/DefaultEnvironment.java
index b8d5ce8cf3d0..a9fb08f216e3 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/DefaultEnvironment.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/DefaultEnvironment.java
@@ -38,6 +38,7 @@ public DefaultEnvironment() {
         this(new HashMap<>());
     }
 
+    @Override
     @SuppressWarnings("unchecked")
     public  T getService(Class clazz) {
         return (T) services.get(clazz);
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/DefaultPackageResolver.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/DefaultPackageResolver.java
index 2087202311b1..42256bc7fc74 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/DefaultPackageResolver.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/DefaultPackageResolver.java
@@ -165,7 +165,7 @@ public Collection resolvePackageMetadata(Collection centralLoadRequests = requests.stream()
                 .filter(r -> !r.packageDescriptor().isBuiltInPackage())
-                .collect(Collectors.toList());
+                .toList();
         Collection latestVersionsInCentral =
                 centralRepo.getPackageMetadata(centralLoadRequests, options);
 
@@ -207,7 +207,7 @@ public Collection resolvePackages(Collection resolvePackage(request, options))
-                .collect(Collectors.toList());
+                .toList();
     }
 
     private ResolutionResponse resolvePackage(ResolutionRequest resolutionReq, ResolutionOptions options) {
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/DefaultProjectEnvironment.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/DefaultProjectEnvironment.java
index 2f978763d6e5..6a9f77ebd4aa 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/DefaultProjectEnvironment.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/DefaultProjectEnvironment.java
@@ -43,6 +43,7 @@ public DefaultProjectEnvironment(Project project, Environment environment, Map T getService(Class clazz) {
         Object service = services.get(clazz);
@@ -53,6 +54,7 @@ public  T getService(Class clazz) {
         return (T) service;
     }
 
+    @Override
     public Environment environment() {
         return environment;
     }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/EnvironmentPackageCache.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/EnvironmentPackageCache.java
index 819dbc4c9912..073ba221d375 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/EnvironmentPackageCache.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/environment/EnvironmentPackageCache.java
@@ -26,6 +26,7 @@ public class EnvironmentPackageCache implements WritablePackageCache {
     private final Map>>
             projectsByOrgNameVersion = new HashMap<>();
 
+    @Override
     public void cache(Package pkg) {
         projectsById.put(pkg.packageId(), pkg.project());
         projectsByOrgNameVersion.computeIfAbsent(pkg.packageOrg(), k -> new HashMap<>())
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/jballerina/JarWriter.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/jballerina/JarWriter.java
deleted file mode 100644
index bceecc59c5cd..000000000000
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/jballerina/JarWriter.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
- *
- * WSO2 Inc. 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.projects.internal.jballerina;
-
-import org.apache.commons.compress.archivers.jar.JarArchiveEntry;
-import org.wso2.ballerinalang.compiler.CompiledJarFile;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.util.Map;
-import java.util.jar.Attributes;
-import java.util.jar.JarEntry;
-import java.util.jar.JarOutputStream;
-import java.util.jar.Manifest;
-
-/**
- * Write jar binary content to target path.
- *
- * @since 2.0.0
- */
-public class JarWriter {
-
-    public static ByteArrayOutputStream write(CompiledJarFile compiledJarFile, Map resources)
-            throws IOException {
-        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-        writeJar(compiledJarFile, byteArrayOutputStream, resources);
-        return byteArrayOutputStream;
-    }
-
-    private static Manifest getManifest(CompiledJarFile compiledJarFile) {
-        Manifest manifest = new Manifest();
-        Attributes mainAttributes = manifest.getMainAttributes();
-        mainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0");
-        compiledJarFile.getMainClassName().ifPresent(mainClassName ->
-                mainAttributes.put(Attributes.Name.MAIN_CLASS, mainClassName));
-        return manifest;
-    }
-
-    private static void writeJar(CompiledJarFile compiledJarFile, OutputStream outputStream,
-                                 Map resources) throws IOException {
-        Manifest manifest = getManifest(compiledJarFile);
-        try (JarOutputStream target = new JarOutputStream(outputStream, manifest)) {
-            Map jarEntries = compiledJarFile.getJarEntries();
-            for (Map.Entry keyVal : jarEntries.entrySet()) {
-                byte[] entryContent = keyVal.getValue();
-                JarEntry entry = new JarEntry(keyVal.getKey());
-                target.putNextEntry(entry);
-                target.write(entryContent);
-                target.closeEntry();
-            }
-
-            // Copy resources
-            for (Map.Entry entry : resources.entrySet()) {
-                JarArchiveEntry e = new JarArchiveEntry(entry.getKey());
-                target.putNextEntry(e);
-                target.write(entry.getValue());
-                target.closeEntry();
-            }
-        }
-    }
-}
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/BalToolDescriptor.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/BalToolDescriptor.java
index b31bf54151d9..b2c6b8003158 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/BalToolDescriptor.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/BalToolDescriptor.java
@@ -36,7 +36,6 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Optional;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 /**
@@ -50,8 +49,8 @@ public class BalToolDescriptor {
     private static final String DEPENDENCY = "dependency";
     public static final String PATH = "path";
 
-    private BalToolDescriptor.Tool tool;
-    private List dependencies;
+    private final BalToolDescriptor.Tool tool;
+    private final List dependencies;
 
     private BalToolDescriptor(BalToolDescriptor.Tool tool, List dependencies) {
         this.tool = tool;
@@ -201,7 +200,7 @@ private static List getDependenciesInDir(String pa
 
         return getToolJarsMatchingPattern(pattern, parentPath.get()).stream()
                 .map(path1 -> new BalToolDescriptor.Dependency(path1.toString()))
-                .collect(Collectors.toList());
+                .toList();
     }
 
     private static List getToolJarsMatchingPattern(String pattern, Path parentPath) {
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/Central.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/Central.java
index 7eac25e6b263..9a3bdbfdc9f0 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/Central.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/Central.java
@@ -28,24 +28,27 @@ public class Central {
     private int readTimeout = 60;
     private int writeTimeout = 60;
     private int callTimeout = 60;
+    private int maxRetries = 1;
 
 
     private Central(String accesstoken, int connectTimeout, int readTimeout, int writeTimeout,
-                    int callTimeout) {
+                    int callTimeout, int maxRetries) {
         this.accesstoken = accesstoken;
         this.connectTimeout = connectTimeout;
         this.readTimeout = readTimeout;
         this.writeTimeout = writeTimeout;
         this.callTimeout = callTimeout;
+        this.maxRetries = maxRetries;
+
     }
 
     public static Central from(String accesstoken, int connectTimeout, int readTimeout, int writeTimeout,
-                               int callTimeout) {
-        return new Central(accesstoken, connectTimeout, readTimeout, writeTimeout, callTimeout);
+                               int callTimeout, int maxRetries) {
+        return new Central(accesstoken, connectTimeout, readTimeout, writeTimeout, callTimeout, maxRetries);
     }
 
     public static Central from() {
-        return new Central("", 60, 60, 60, 0);
+        return new Central("", 60, 60, 60, 0, 1);
     }
 
     /**
@@ -93,6 +96,15 @@ public int getCallTimeout() {
         return callTimeout;
     }
 
+    /**
+     * Get the max retries.
+     *
+     * @return max retries
+     */
+    public int getMaxRetries() {
+        return maxRetries;
+    }
+
     /**
      * Sets the value of the access token.
      *
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/CompilerPluginDescriptor.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/CompilerPluginDescriptor.java
index bf4a255cd451..693990b375c6 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/CompilerPluginDescriptor.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/CompilerPluginDescriptor.java
@@ -40,8 +40,8 @@ public class CompilerPluginDescriptor {
     private static final String DEPENDENCY = "dependency";
     private static final String CLASS = "class";
 
-    private Plugin plugin;
-    private List dependencies;
+    private final Plugin plugin;
+    private final List dependencies;
 
     private CompilerPluginDescriptor(Plugin plugin, List dependencies) {
         this.plugin = plugin;
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/Repository.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/Repository.java
index dcdba2e542b1..376ff2d979db 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/Repository.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/Repository.java
@@ -22,10 +22,10 @@
  * @since 2201.8.0
  */
 public class Repository {
-    private String id;
-    private String url;
-    private String username;
-    private String password;
+    private final String id;
+    private final String url;
+    private final String username;
+    private final String password;
 
     private Repository(String id, String url, String username, String password) {
         this.id = id;
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/Target.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/Target.java
index b2befaa7a98d..5a11c9eb201b 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/Target.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/model/Target.java
@@ -17,6 +17,7 @@
  */
 package io.ballerina.projects.internal.model;
 
+import io.ballerina.projects.Module;
 import io.ballerina.projects.Package;
 import io.ballerina.projects.util.ProjectConstants;
 import io.ballerina.projects.util.ProjectUtils;
@@ -34,17 +35,18 @@
 public class Target {
     private final Path targetPath;
     private Path outputPath = null;
-    private Path cache;
-    private Path jarCachePath;
-    private Path balaCachePath;
-    private Path birCachePath;
-    private Path testsCachePath;
-    private Path binPath;
-    private Path reportPath;
-    private Path docPath;
-    private Path nativePath;
-    private Path nativeConfigPath;
-    private Path profilerPath;
+    private final Path cache;
+    private final Path jarCachePath;
+    private final Path balaCachePath;
+    private final Path birCachePath;
+    private final Path testsCachePath;
+    private final Path binPath;
+    private final Path reportPath;
+    private final Path docPath;
+    private final Path nativePath;
+    private final Path nativeConfigPath;
+    private final Path profilerPath;
+    private final Path resourcesPath;
 
     public Target(Path targetPath) throws IOException {
         this.targetPath = targetPath;
@@ -59,6 +61,7 @@ public Target(Path targetPath) throws IOException {
         this.nativePath = this.targetPath.resolve(ProjectConstants.NATIVE_DIR_NAME);
         this.nativeConfigPath = this.testsCachePath.resolve(ProjectConstants.NATIVE_CONFIG_DIR_NAME);
         this.profilerPath = this.targetPath.resolve(ProjectConstants.PROFILER_DIR_NAME);
+        this.resourcesPath = this.targetPath.resolve(ProjectConstants.RESOURCE_DIR_NAME);
 
         if (Files.exists(this.targetPath)) {
             ProjectUtils.checkWritePermission(this.targetPath);
@@ -85,6 +88,9 @@ public Target(Path targetPath) throws IOException {
         if (Files.exists(this.profilerPath)) {
             ProjectUtils.checkWritePermission(this.profilerPath);
         }
+        if (Files.exists(this.resourcesPath)) {
+            ProjectUtils.checkWritePermission(this.resourcesPath);
+        }
     }
 
     /**
@@ -130,6 +136,24 @@ public Path getExecutablePath(Package pkg) throws IOException {
         return getBinPath().resolve(ProjectUtils.getExecutableName(pkg));
     }
 
+    public Path getTestExecutablePath(Module module) throws IOException {
+        if (outputPath != null) {
+            return outputPath;
+        }
+        String name = module.moduleName().toString();
+        return getTestBinPath().resolve(name +
+                ProjectConstants.TEST_UBER_JAR_SUFFIX +
+                ProjectConstants.BLANG_COMPILED_JAR_EXT);
+    }
+
+    public Path getTestExecutableBasePath() throws IOException {
+        if (outputPath != null) {
+            return outputPath.getParent();
+        }
+
+        return getTestBinPath();
+    }
+
     /**
      * Returns the bin directory path.
      *
@@ -140,6 +164,11 @@ public Path getBinPath() throws IOException {
         return binPath;
     }
 
+    public Path getTestBinPath() throws IOException {
+        Files.createDirectories(binPath.resolve(ProjectConstants.TEST_DIR_NAME));
+        return binPath.resolve(ProjectConstants.TEST_DIR_NAME);
+    }
+
     public Path getReportPath() throws IOException {
         Files.createDirectories(reportPath);
         return reportPath;
@@ -213,7 +242,7 @@ public void setOutputPath(Path outputPath) throws IOException {
     /**
      * Clean any files that created from the build.
      */
-    public void clean(boolean isModified, boolean cacheEnabled) throws IOException {
+    public void clean(boolean isModified, boolean cacheEnabled) {
         if (isModified || !cacheEnabled) {
             // Remove from cache
             ProjectUtils.deleteDirectory(this.cache);
@@ -224,12 +253,13 @@ public void clean(boolean isModified, boolean cacheEnabled) throws IOException {
         ProjectUtils.deleteDirectory(this.binPath);
         ProjectUtils.deleteDirectory(this.docPath);
         ProjectUtils.deleteDirectory(this.reportPath);
+        ProjectUtils.deleteDirectory(this.resourcesPath);
     }
 
     /**
      * Clean cache files that created from the build.
      */
-    public void cleanCache() throws IOException {
+    public void cleanCache() {
         // Remove from cache
         ProjectUtils.deleteDirectory(this.cache);
     }
@@ -243,4 +273,8 @@ public Path getNativeConfigPath() throws IOException {
         Files.createDirectories(nativeConfigPath);
         return nativeConfigPath;
     }
+
+    public void cleanBinTests() {
+        ProjectUtils.deleteDirectory(this.binPath.resolve(ProjectConstants.TEST_DIR_NAME));
+    }
 }
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/plugins/CompilerPlugins.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/plugins/CompilerPlugins.java
index df4d15075e91..9c79bfcb0685 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/plugins/CompilerPlugins.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/plugins/CompilerPlugins.java
@@ -41,7 +41,8 @@
  *
  * @since 2.0.0
  */
-public class CompilerPlugins {
+public final class CompilerPlugins {
+
     static List builtInPlugins = new ArrayList<>();
 
     private CompilerPlugins() {
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/AbstractPackageRepository.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/AbstractPackageRepository.java
index 6bc031528eff..f9c59655922a 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/AbstractPackageRepository.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/AbstractPackageRepository.java
@@ -35,7 +35,6 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Comparator;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -128,10 +127,10 @@ private ImportModuleResponse getImportModuleLoadResponse(ImportModuleRequest imp
         // If the module is not found in the possible packages locked in the Dependencies.toml
         // we continue looking for the module in the remaining possible packages.
         List existing = importModuleRequest.possiblePackages().stream().map(PackageDescriptor::name)
-                .collect(Collectors.toList());
+                .toList();
         List remainingPackageNames = ProjectUtils.getPossiblePackageNames(
                 importModuleRequest.packageOrg(), importModuleRequest.moduleName()).stream()
-                .filter(o -> !existing.contains(o)).collect(Collectors.toList());
+                .filter(o -> !existing.contains(o)).toList();
 
         for (PackageName possiblePackageName : remainingPackageNames) {
             List packageVersions = getPackageVersions(importModuleRequest.packageOrg(),
@@ -149,15 +148,16 @@ private ImportModuleResponse getImportModuleLoadResponse(ImportModuleRequest imp
     private ImportModuleResponse getImportModuleResponse(ImportModuleRequest importModuleRequest,
                                                          PackageName packageName,
                                                          List packageVersions) {
-        Comparator comparator = (v1, v2) -> {
-
+        packageVersions.sort((v1, v2) -> {
+            if (v1.equals(v2)) {
+                return 0;
+            }
             PackageVersion latest = getLatest(v1, v2);
             if (v1 == latest) {
                 return -1;
             }
             return 1;
-        };
-        packageVersions.sort(comparator);
+        });
 
         for (PackageVersion packageVersion : packageVersions) {
             Collection moduleDescriptors = getModules(
diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/FileSystemRepository.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/FileSystemRepository.java
index ff2532a39075..79a236328616 100644
--- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/FileSystemRepository.java
+++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/FileSystemRepository.java
@@ -45,26 +45,25 @@
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 /**
  * Package Repository stored in file system.
- * The structure of the repository is as bellow
+ * The structure of the repository is as below
+ * 
  * - bala
  *     - org
  *         - package-name
  *             - version
  *                 - platform (contains extracted bala)
  *
- * - cache[-]
+ * - cache[-<distShortVersion>]
  *     - org
  *         - package-name
  *             - version
@@ -73,7 +72,7 @@
  *                     - mod2.bir
  *                 - jar
  *                     - org-package-name-version.jar
- *
+ * 
* @since 2.0.0 */ public class FileSystemRepository extends AbstractPackageRepository { @@ -123,7 +122,7 @@ void updateDeprecatedStatusForPackage(PackageDescriptor descriptor) { Path balaPath = getPackagePath(descriptor.org().value(), descriptor.name().value(), descriptor.version().value().toString()); if (balaPath != null && Files.exists(balaPath)) { - Path deprecateMsgMetaFile = Paths.get(balaPath.toString(), ProjectConstants.DEPRECATED_META_FILE_NAME); + Path deprecateMsgMetaFile = Path.of(balaPath.toString(), ProjectConstants.DEPRECATED_META_FILE_NAME); if (descriptor.getDeprecated() && !deprecateMsgMetaFile.toFile().exists()) { FileUtils.addDeprecatedMetaFile(deprecateMsgMetaFile, descriptor.getDeprecationMsg()); } @@ -138,6 +137,9 @@ void updateDeprecatedStatusForPackage(PackageDescriptor descriptor) { public boolean isPackageExists(PackageOrg org, PackageName name, PackageVersion version) { + if (org.value() == null || name.value() == null) { + return false; + } Path balaPath = getPackagePath(org.value(), name.value(), version.value().toString()); return Files.exists(balaPath); } @@ -154,6 +156,7 @@ public Collection getPackageVersions(ResolutionRequest request, * * @return {@link List} of package names */ + @Override public Map> getPackages() { Map> packagesMap = new HashMap<>(); File[] orgDirs = this.bala.toFile().listFiles(); @@ -203,13 +206,14 @@ public Map> getPackages() { return packagesMap; } + @Override protected List getPackageVersions(PackageOrg org, PackageName name, PackageVersion version) { List versions = new ArrayList<>(); try { Path balaPackagePath = bala.resolve(org.value()).resolve(name.value()); if (Files.exists(balaPackagePath)) { try (Stream collect = Files.list(balaPackagePath)) { - versions.addAll(collect.collect(Collectors.toList())); + versions.addAll(collect.toList()); } } } catch (IOException e) { diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/LocalPackageRepository.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/LocalPackageRepository.java index 04c1c5a435ef..40f9a2c7a066 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/LocalPackageRepository.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/LocalPackageRepository.java @@ -41,6 +41,7 @@ public LocalPackageRepository(Environment environment, Path cacheDirectory, Stri super(environment, cacheDirectory, distributionVersion); } + @Override protected List getPackageVersions(PackageOrg org, PackageName name, PackageVersion version) { if (version == null) { return Collections.emptyList(); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/MavenPackageRepository.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/MavenPackageRepository.java index 0791f2305a60..638fce6e91df 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/MavenPackageRepository.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/MavenPackageRepository.java @@ -36,16 +36,13 @@ import org.apache.commons.io.FileUtils; import org.ballerinalang.maven.bala.client.MavenResolverClient; import org.ballerinalang.maven.bala.client.MavenResolverClientException; -import org.ballerinalang.toml.exceptions.SettingsTomlException; import org.wso2.ballerinalang.util.RepoUtils; - import java.io.BufferedReader; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -92,11 +89,7 @@ public static MavenPackageRepository from(Environment environment, Path cacheDir } Settings settings; - try { - settings = RepoUtils.readSettings(); - } catch (SettingsTomlException e) { - settings = Settings.from(); - } + settings = RepoUtils.readSettings(); Proxy proxy = settings.getProxy(); mvnClient.setProxy(proxy.host(), proxy.port(), proxy.username(), proxy.password()); @@ -190,7 +183,7 @@ public boolean getPackageFromRemoteRepo(String org, try (BufferedReader bufferedReader = Files.newBufferedReader(packageJsonPath, StandardCharsets.UTF_8)) { JsonObject resultObj = new Gson().fromJson(bufferedReader, JsonObject.class); String platform = resultObj.get(PLATFORM).getAsString(); - Path actualBalaPath = Paths.get(this.repoLocation).resolve(org).resolve(name) + Path actualBalaPath = Path.of(this.repoLocation).resolve(org).resolve(name) .resolve(version).resolve(platform); FileUtils.copyDirectory(temporaryExtractionPath.toFile(), actualBalaPath.toFile()); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/RemotePackageRepository.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/RemotePackageRepository.java index 8990fafc81b3..0e5a05f6fb48 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/RemotePackageRepository.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/repositories/RemotePackageRepository.java @@ -78,7 +78,7 @@ public static RemotePackageRepository from(Environment environment, Path cacheDi settings.getProxy().password(), getAccessTokenOfCLI(settings), settings.getCentral().getConnectTimeout(), settings.getCentral().getReadTimeout(), settings.getCentral().getWriteTimeout(), - settings.getCentral().getCallTimeout()); + settings.getCentral().getCallTimeout(), settings.getCentral().getMaxRetries()); return new RemotePackageRepository(fileSystemRepository, client); } @@ -260,6 +260,7 @@ private PackageNameResolutionRequest toPackageNameResolutionRequest(Collection getPackageMetadata(Collection requests, ResolutionOptions options) { if (requests.isEmpty()) { @@ -415,18 +416,11 @@ private static DependencyGraph createPackageDependencyGraph( private PackageResolutionRequest toPackageResolutionRequest(Collection resolutionRequests) { PackageResolutionRequest packageResolutionRequest = new PackageResolutionRequest(); for (ResolutionRequest resolutionRequest : resolutionRequests) { - PackageResolutionRequest.Mode mode = PackageResolutionRequest.Mode.HARD; - switch (resolutionRequest.packageLockingMode()) { - case HARD: - mode = PackageResolutionRequest.Mode.HARD; - break; - case MEDIUM: - mode = PackageResolutionRequest.Mode.MEDIUM; - break; - case SOFT: - mode = PackageResolutionRequest.Mode.SOFT; - break; - } + PackageResolutionRequest.Mode mode = switch (resolutionRequest.packageLockingMode()) { + case HARD -> PackageResolutionRequest.Mode.HARD; + case MEDIUM -> PackageResolutionRequest.Mode.MEDIUM; + case SOFT -> PackageResolutionRequest.Mode.SOFT; + }; String version = resolutionRequest.version().map(v -> v.value().toString()).orElse(""); packageResolutionRequest.addPackage(resolutionRequest.orgName().value(), resolutionRequest.packageName().value(), diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/CompilerLifecycleEventContext.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/CompilerLifecycleEventContext.java index f4a8b734205e..910d4ddd4689 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/CompilerLifecycleEventContext.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/CompilerLifecycleEventContext.java @@ -17,6 +17,7 @@ */ package io.ballerina.projects.plugins; +import io.ballerina.projects.BalCommand; import io.ballerina.projects.Package; import io.ballerina.projects.PackageCompilation; import io.ballerina.tools.diagnostics.Diagnostic; @@ -59,4 +60,5 @@ public interface CompilerLifecycleEventContext { * @return path to the generated artifact. */ public Optional getGeneratedArtifactPath(); + public BalCommand balCommand(); } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/CompilerPluginContext.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/CompilerPluginContext.java index fc681455f67a..326628f29887 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/CompilerPluginContext.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/CompilerPluginContext.java @@ -17,6 +17,7 @@ */ package io.ballerina.projects.plugins; +import io.ballerina.compiler.syntax.tree.Node; import io.ballerina.projects.plugins.codeaction.CodeAction; import io.ballerina.projects.plugins.completion.CompletionProvider; @@ -69,12 +70,12 @@ public interface CompilerPluginContext { * * @param completionProvider the {@link CompletionProvider} instance */ - void addCompletionProvider(CompletionProvider completionProvider); + void addCompletionProvider(CompletionProvider completionProvider); /** * Returns user data for the compiler plugin. * - * @return Map of user data as Map + * @return Map of user data as {@link Map Map<String, Object>} */ Map userData(); } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/SourceGeneratorContext.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/SourceGeneratorContext.java index ba98b9ff0875..9f93d4da56b3 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/SourceGeneratorContext.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/SourceGeneratorContext.java @@ -84,6 +84,7 @@ public interface SourceGeneratorContext { * @param content a {@code TextDocument} that contains the source code * @param fileName proposed prefix of the filename to be added */ + @Deprecated(since = "2201.10.0", forRemoval = true) void addResourceFile(byte[] content, String fileName, ModuleId moduleId); /** @@ -92,6 +93,7 @@ public interface SourceGeneratorContext { * @param content a {@code TextDocument} that contains the source code * @param fileName proposed prefix of the filename to be added */ + @Deprecated(since = "2201.10.0", forRemoval = true) void addResourceFile(byte[] content, String fileName); /** @@ -100,6 +102,7 @@ public interface SourceGeneratorContext { * @param content a {@code TextDocument} that contains the test resource content * @param fileName proposed prefix of the filename to be added */ + @Deprecated(since = "2201.10.0", forRemoval = true) void addTestResourceFile(byte[] content, String fileName, ModuleId moduleId); /** @@ -108,6 +111,7 @@ public interface SourceGeneratorContext { * @param content a {@code TextDocument} that contains the test resource content * @param fileName proposed prefix of the filename to be added */ + @Deprecated(since = "2201.10.0", forRemoval = true) void addTestResourceFile(byte[] content, String fileName); /** diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/CodeActionArgument.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/CodeActionArgument.java index b849b3ae88fe..73fb5bb36fa7 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/CodeActionArgument.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/CodeActionArgument.java @@ -28,8 +28,8 @@ public class CodeActionArgument { private static final Gson GSON = new Gson(); - private String key; - private Object value; + private final String key; + private final Object value; private CodeActionArgument(String argumentK, Object value) { this.key = argumentK; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/CodeActionContextImpl.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/CodeActionContextImpl.java index a1c1749faa38..69175474f2b0 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/CodeActionContextImpl.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/CodeActionContextImpl.java @@ -29,7 +29,7 @@ */ public class CodeActionContextImpl extends PositionedActionContextImpl implements CodeActionContext { - private Diagnostic diagnostic; + private final Diagnostic diagnostic; private CodeActionContextImpl(String fileUri, Path filePath, LinePosition cursorPosition, Document document, SemanticModel semanticModel, Diagnostic diagnostic) { diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/CodeActionExecutionContextImpl.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/CodeActionExecutionContextImpl.java index ab1d0c27ccc9..fd98c7959a84 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/CodeActionExecutionContextImpl.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/CodeActionExecutionContextImpl.java @@ -29,7 +29,7 @@ */ public class CodeActionExecutionContextImpl extends PositionedActionContextImpl implements CodeActionExecutionContext { - private List arguments; + private final List arguments; private CodeActionExecutionContextImpl(String fileUri, Path filePath, LinePosition cursorPosition, Document document, SemanticModel semanticModel, diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/DocumentEdit.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/DocumentEdit.java index 673f527ed6b5..02d5f18b7c30 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/DocumentEdit.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/DocumentEdit.java @@ -25,8 +25,8 @@ */ public class DocumentEdit { - private String fileUri; - private SyntaxTree modifiedSyntaxTree; + private final String fileUri; + private final SyntaxTree modifiedSyntaxTree; public DocumentEdit(String fileUri, SyntaxTree modifiedSyntaxTree) { this.fileUri = fileUri; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/PositionedActionContext.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/PositionedActionContext.java index 075b1f105ba2..5bb7365eb073 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/PositionedActionContext.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/codeaction/PositionedActionContext.java @@ -39,7 +39,7 @@ public interface PositionedActionContext { /** * Get the file path. * - * @return {@link java.nio.file.Path} file path + * @return {@link Path} file path */ Path filePath(); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/completion/CompletionException.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/completion/CompletionException.java index 85a5a654db53..50c6bd031c2f 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/completion/CompletionException.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/completion/CompletionException.java @@ -21,7 +21,7 @@ * @since 2201.7.0 */ public class CompletionException extends RuntimeException { - private String providerName; + private final String providerName; public CompletionException(Throwable cause, String providerName) { super(cause); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/completion/CompletionItem.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/completion/CompletionItem.java index 888f3f4222f3..7770c5e4a9e8 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/completion/CompletionItem.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/completion/CompletionItem.java @@ -29,12 +29,12 @@ public class CompletionItem { * The label of this completion item. By default, also the text that is inserted when selecting * this completion. */ - private String label; + private final String label; /** * Indicates the priority(sorted position) of the completion item. */ - private Priority priority; + private final Priority priority; /** * An optional array of additional text edits that are applied when selecting this completion. @@ -49,7 +49,7 @@ public class CompletionItem { * A string that should be inserted a document when selecting this completion. * When omitted or empty, the label is used as the insert text for this item. */ - private String insertText; + private final String insertText; public CompletionItem(String label, String insertText, Priority priority) { this.label = label; diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/completion/CompletionUtil.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/completion/CompletionUtil.java index fd7cacb6c8a4..88f08a1b51b6 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/completion/CompletionUtil.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/plugins/completion/CompletionUtil.java @@ -20,11 +20,14 @@ * * @since 2201.7.0 */ -public class CompletionUtil { +public final class CompletionUtil { public static final String LINE_BREAK = System.lineSeparator(); public static final String PADDING = "\t"; + private CompletionUtil() { + } + public static String getPlaceHolderText(int index, String defaultValue) { return "${" + index + ":" + defaultValue + "}"; } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/repos/FileSystemCache.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/repos/FileSystemCache.java index 44b1a5e00d6f..78b6eef2e60e 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/repos/FileSystemCache.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/repos/FileSystemCache.java @@ -171,6 +171,7 @@ public FileSystemCacheFactory(Path cacheDirPath) { this.cacheDirPath = cacheDirPath; } + @Override public CompilationCache createCompilationCache(Project project) { return new FileSystemCache(project, cacheDirPath); } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/BuildToolUtils.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/BuildToolUtils.java index ec9e87dee624..0d68e70e11e6 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/BuildToolUtils.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/BuildToolUtils.java @@ -56,7 +56,8 @@ * * @since 2201.9.0 */ -public class BuildToolUtils { +public final class BuildToolUtils { + private BuildToolUtils() {} /** diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/DependencyUtils.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/DependencyUtils.java index 41a637b7a96d..5bd9e06496fe 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/DependencyUtils.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/DependencyUtils.java @@ -25,7 +25,7 @@ * * @since 2.0.0 */ -public class DependencyUtils { +public final class DependencyUtils { private DependencyUtils() { diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/FileUtils.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/FileUtils.java index 44814f394fef..4ee6c4eaa9ce 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/FileUtils.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/FileUtils.java @@ -34,7 +34,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; -import java.nio.file.Paths; import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; @@ -42,7 +41,6 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; import java.util.stream.Stream; import static io.ballerina.projects.util.ProjectConstants.BALLERINA_TOML; @@ -60,11 +58,14 @@ * * @since 2.0.0 */ -public class FileUtils { +public final class FileUtils { private static final String PNG_HEX_HEADER = "89504E470D0A1A0A"; private static final PathMatcher FILE_MATCHER = FileSystems.getDefault().getPathMatcher("glob:**/Ballerina.toml"); + private FileUtils() { + } + /** * Get the name of the without the extension. * @@ -72,7 +73,7 @@ public class FileUtils { * @return File name without extension. */ public static String getFileNameWithoutExtension(String filePath) { - Path fileName = Paths.get(filePath).getFileName(); + Path fileName = Path.of(filePath).getFileName(); if (null != fileName) { int index = indexOfExtension(fileName.toString()); return index == -1 ? fileName.toString() : @@ -170,8 +171,10 @@ public static void deletePath(Path path) throws IOException { } if (Files.isDirectory(path)) { - for (Path dir : Files.list(path).collect(Collectors.toList())) { - deletePath(dir); + try (Stream paths = Files.list(path)) { + for (Path dir : paths.toList()) { + deletePath(dir); + } } } @@ -310,7 +313,8 @@ public static void replaceTemplateName(Path path, String templateName, String pa Files.write(path, content.getBytes(StandardCharsets.UTF_8)); } } catch (IOException e) { - throw new RuntimeException("Error while replacing template name in module import statements: " + path, e); + throw new RuntimeException( + "Error while replacing template name in module import statements: " + path, e); } } } @@ -335,11 +339,11 @@ public static List getFilesInDirectory(Path directoryPath) { * Copy files to the given destination. */ public static class Copy extends SimpleFileVisitor { - private Path fromPath; - private Path toPath; - private String templateName; - private String packageName; - private StandardCopyOption copyOption; + private final Path fromPath; + private final Path toPath; + private final String templateName; + private final String packageName; + private final StandardCopyOption copyOption; public Copy(Path fromPath, Path toPath, String templateName, String packageName, @@ -397,7 +401,7 @@ public static boolean checkBallerinaTomlInExistingDir(Path startingDir) { * Look for existing Ballerina.toml file in the given directory up to 10 levels. */ public static class BallerinaTomlChecker extends SimpleFileVisitor { - private Path startingPath; + private final Path startingPath; private boolean ballerinaTomlFound = false; public boolean isBallerinaTomlFound() { @@ -413,8 +417,7 @@ public BallerinaTomlChecker(Path startingPath) { } @Override - public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) - throws IOException { + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { int depth = dir.getNameCount() - startingPath.getNameCount(); if (depth >= 10) { @@ -424,8 +427,7 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) } @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) - throws IOException { + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) { if (FILE_MATCHER.matches(file)) { setBallerinaTomlFound(true); diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectConstants.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectConstants.java index 149440120bc3..ec059e250ae7 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectConstants.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectConstants.java @@ -16,20 +16,19 @@ * under the License. */ package io.ballerina.projects.util; - - /** * Defines constants related to the project directory. * * @since 2.0.0 */ -public class ProjectConstants { +public final class ProjectConstants { private ProjectConstants() {} public static final String BLANG_SOURCE_EXT = ".bal"; public static final String BALA_EXTENSION = ".bala"; public static final String PLATFORM = "platform"; + public static final String TOML_EXTENSION = ".toml"; public static final String BALLERINA_TOML = "Ballerina.toml"; public static final String DEPENDENCIES_TOML = "Dependencies.toml"; @@ -51,6 +50,7 @@ private ProjectConstants() {} public static final String DEPENDENCY_GRAPH_JSON = "dependency-graph.json"; public static final String DEPRECATED_META_FILE_NAME = "deprecated.txt"; public static final String BUILD_FILE = "build"; + public static final String JAVA_CLASS_EXT = ".class"; public static final String SOURCE_DIR_NAME = "src"; public static final String BIN_DIR_NAME = "bin"; @@ -99,6 +99,7 @@ private ProjectConstants() {} public static final String ANON_ORG = "$anon"; public static final String DOT = "."; + public static final String EQUAL = "="; public static final String DEFAULT_VERSION = "0.0.0"; public static final String INTERNAL_VERSION = "0.1.0"; public static final String MODULE_NAME_SEPARATOR = DOT; @@ -112,13 +113,19 @@ private ProjectConstants() {} // Test framework related constants public static final String TEST_RUNTIME_JAR_PREFIX = "testerina-runtime-"; public static final String TEST_CORE_JAR_PREFIX = "testerina-core-"; + public static final String TEST_UBER_JAR_SUFFIX = "-testable"; + public static final String DIR_PATH_SEPARATOR = "/"; + public static final String TEST_RUNTIME_MAIN_ARGS_FILE = "mainArgs.txt"; + public static final String EXCLUDED_CLASSES_FILE = "excludedClasses.txt"; + public static final String TEST_SUITE = "test_suite"; + public static final String TEST_SUITE_JSON = "test_suit.json"; - public static final String JACOCO_CORE_JAR = "org.jacoco.core-0.8.10.jar"; - public static final String JACOCO_REPORT_JAR = "org.jacoco.report-0.8.10.jar"; - public static final String ASM_JAR = "asm-9.5.jar"; - public static final String ASM_TREE_JAR = "asm-tree-9.5.jar"; - public static final String ASM_COMMONS_JAR = "asm-commons-9.5.jar"; + public static final String JACOCO_CORE_JAR = "org.jacoco.core-0.8.12.jar"; + public static final String JACOCO_REPORT_JAR = "org.jacoco.report-0.8.12.jar"; + public static final String ASM_JAR = "asm-9.7.jar"; + public static final String ASM_TREE_JAR = "asm-tree-9.7.jar"; + public static final String ASM_COMMONS_JAR = "asm-commons-9.7.jar"; public static final String DIFF_UTILS_JAR = "java-diff-utils-4.5.jar"; public static final String REPORT_DIR_NAME = "report"; @@ -138,4 +145,8 @@ private ProjectConstants() {} public static final String ORG = "org"; public static final String PACKAGE_NAME = "name"; public static final String LOCAL_TOOLS_JSON = "local-tools.json"; + public static final String STICKY_FLAG = "--sticky"; + public static final String OFFLINE_FLAG = "--offline"; + public static final String REPOSITORY_FLAG = "--repository"; + public static final String WILD_CARD = "*"; } diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectPaths.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectPaths.java index ece202a30f84..f61afc07fbdc 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectPaths.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectPaths.java @@ -33,7 +33,10 @@ * * @since 2.0.0 */ -public class ProjectPaths { +public final class ProjectPaths { + + private ProjectPaths() { + } /** * Finds the root directory of a Ballerina package using the filepath provided. @@ -45,7 +48,7 @@ public class ProjectPaths { public static Path packageRoot(Path filepath) throws ProjectException { // check if the file exists if (!Files.exists(filepath)) { - throw new ProjectException("provided path does not exist:" + filepath); + throw new ProjectException("'" + filepath + "'" + " does not exist"); } if (Files.isDirectory(filepath)) { @@ -62,7 +65,7 @@ public static Path packageRoot(Path filepath) throws ProjectException { // check if the file is a regular file if (!Files.isRegularFile(filepath)) { - throw new ProjectException("provided path is not a regular file: " + filepath); + throw new ProjectException("'" + filepath + "'" + " is not a regular file"); } // Check if the file is inside a Ballerina package directory @@ -79,7 +82,7 @@ public static Path packageRoot(Path filepath) throws ProjectException { } if (!isBalFile(filepath)) { - throw new ProjectException("provided path is not a valid Ballerina source file: " + filepath); + throw new ProjectException("'" + filepath + "' is not a valid Ballerina source file"); } // check if the file is a source file in the default module @@ -238,15 +241,13 @@ public static boolean isBalFile(Path filepath) { */ private static boolean isBallerinaRelatedToml(Path filepath) { String fileName = Optional.of(filepath.getFileName()).get().toString(); - switch (fileName) { - case ProjectConstants.BALLERINA_TOML: - case ProjectConstants.CLOUD_TOML: - case ProjectConstants.CONFIGURATION_TOML: - case ProjectConstants.DEPENDENCIES_TOML: - return true; - default: - return false; - } + return switch (fileName) { + case ProjectConstants.BALLERINA_TOML, + ProjectConstants.CLOUD_TOML, + ProjectConstants.CONFIGURATION_TOML, + ProjectConstants.DEPENDENCIES_TOML -> true; + default -> false; + }; } /** diff --git a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectUtils.java b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectUtils.java index 1012b6d88f37..da43638ffb7d 100644 --- a/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectUtils.java +++ b/compiler/ballerina-lang/src/main/java/io/ballerina/projects/util/ProjectUtils.java @@ -24,6 +24,7 @@ import io.ballerina.compiler.syntax.tree.ImportDeclarationNode; import io.ballerina.compiler.syntax.tree.ModulePartNode; import io.ballerina.compiler.syntax.tree.SeparatedNodeList; +import io.ballerina.compiler.syntax.tree.SyntaxKind; import io.ballerina.projects.Document; import io.ballerina.projects.DocumentId; import io.ballerina.projects.JarLibrary; @@ -49,12 +50,13 @@ import io.ballerina.projects.internal.model.BuildJson; import io.ballerina.projects.internal.model.Dependency; import io.ballerina.projects.internal.model.ToolDependency; +import io.ballerina.tools.diagnostics.Diagnostic; +import io.ballerina.tools.diagnostics.DiagnosticSeverity; import org.apache.commons.compress.archivers.jar.JarArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveEntryPredicate; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; import org.apache.commons.compress.archivers.zip.ZipFile; import org.ballerinalang.compiler.BLangCompilerException; -import org.wso2.ballerinalang.compiler.CompiledJarFile; import org.wso2.ballerinalang.compiler.util.Names; import org.wso2.ballerinalang.util.Lists; import org.wso2.ballerinalang.util.RepoUtils; @@ -69,11 +71,11 @@ import java.net.InetSocketAddress; import java.net.Proxy; import java.nio.charset.StandardCharsets; +import java.nio.file.DirectoryStream; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -86,12 +88,10 @@ import java.util.Set; import java.util.StringJoiner; import java.util.jar.Attributes; -import java.util.jar.JarFile; import java.util.jar.JarOutputStream; import java.util.jar.Manifest; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -108,27 +108,36 @@ import static io.ballerina.projects.util.ProjectConstants.BUILD_FILE; import static io.ballerina.projects.util.ProjectConstants.CACHES_DIR_NAME; import static io.ballerina.projects.util.ProjectConstants.DIFF_UTILS_JAR; +import static io.ballerina.projects.util.ProjectConstants.DIR_PATH_SEPARATOR; +import static io.ballerina.projects.util.ProjectConstants.DOT; import static io.ballerina.projects.util.ProjectConstants.JACOCO_CORE_JAR; import static io.ballerina.projects.util.ProjectConstants.JACOCO_REPORT_JAR; import static io.ballerina.projects.util.ProjectConstants.LIB_DIR; +import static io.ballerina.projects.util.ProjectConstants.RESOURCE_DIR_NAME; import static io.ballerina.projects.util.ProjectConstants.TARGET_DIR_NAME; import static io.ballerina.projects.util.ProjectConstants.TEST_CORE_JAR_PREFIX; import static io.ballerina.projects.util.ProjectConstants.TEST_RUNTIME_JAR_PREFIX; import static io.ballerina.projects.util.ProjectConstants.TOOL_DIR; import static io.ballerina.projects.util.ProjectConstants.USER_NAME; +import static io.ballerina.projects.util.ProjectConstants.WILD_CARD; /** * Project related util methods. * * @since 2.0.0 */ -public class ProjectUtils { +public final class ProjectUtils { + private static final String USER_HOME = "user.home"; private static final Pattern separatedIdentifierPattern = Pattern.compile("^[a-zA-Z0-9_.]*$"); private static final Pattern onlyDotsPattern = Pattern.compile("^[.]+$"); private static final Pattern onlyNonAlphanumericPattern = Pattern.compile("^[^a-zA-Z0-9]+$"); private static final Pattern orgNamePattern = Pattern.compile("^[a-zA-Z0-9_]*$"); private static final Pattern separatedIdentifierWithHyphenPattern = Pattern.compile("^[a-zA-Z0-9_.-]*$"); + private static String projectLoadingDiagnostic; + + private ProjectUtils() { + } /** * Validates the org-name. @@ -197,10 +206,18 @@ public static Set getPackageImports(Package pkg) { private static void getPackageImports(Set imports, Module module, Collection documentIds) { for (DocumentId docId : documentIds) { Document document = module.document(docId); - ModulePartNode modulePartNode = document.syntaxTree().rootNode(); - for (ImportDeclarationNode importDcl : modulePartNode.imports()) { + boolean isErrorInImport = false; + for (Diagnostic diagnostic : importDcl.diagnostics()) { + if (diagnostic.diagnosticInfo().severity() == DiagnosticSeverity.ERROR) { + isErrorInImport = true; + break; + } + } + if (isErrorInImport) { + continue; + } String orgName = ""; if (importDcl.orgName().isPresent()) { orgName = importDcl.orgName().get().orgName().text(); @@ -388,7 +405,7 @@ public static String guessPkgName(String packageName, String template) { // if package name has consecutive underscores, replace them with a single underscore if (packageName.contains("__")) { - packageName = packageName.replaceAll("__", "_"); + packageName = packageName.replace("__", "_"); } // if package name has trailing underscore remove it @@ -434,7 +451,7 @@ public static String getBalaName(PackageManifest pkgDesc) { public static String getBalaName(String org, String pkgName, String version, String platform) { // ---.bala - if (platform == null || "".equals(platform)) { + if (platform == null || platform.isEmpty()) { platform = "any"; } return org + "-" + pkgName + "-" + platform + "-" + version + BLANG_COMPILED_PKG_BINARY_EXT; @@ -451,10 +468,10 @@ public static String getBalaName(String org, String pkgName, String version, Str */ public static Path getRelativeBalaPath(String org, String pkgName, String version, String platform) { // ---.bala - if (platform == null || "".equals(platform)) { + if (platform == null || platform.isEmpty()) { platform = "any"; } - return Paths.get(org, pkgName, version, platform); + return Path.of(org, pkgName, version, platform); } public static String getJarFileName(Package pkg) { @@ -486,7 +503,7 @@ public static String getVersionFromBalaName(String balaName) { private static final HashSet excludeExtensions = new HashSet<>(Lists.of("DSA", "SF")); public static Path getBalHomePath() { - return Paths.get(System.getProperty(BALLERINA_HOME)); + return Path.of(System.getProperty(BALLERINA_HOME)); } public static Path getBallerinaRTJarPath() { @@ -537,43 +554,6 @@ public static Path generateObservabilitySymbolsJar(String packageName) throws IO return jarPath; } - public static void assembleExecutableJar(Manifest manifest, - List compiledPackageJarList, - Path targetPath) throws IOException { - - // Used to prevent adding duplicated entries during the final jar creation. - HashSet copiedEntries = new HashSet<>(); - - try (ZipArchiveOutputStream outStream = new ZipArchiveOutputStream( - new BufferedOutputStream(new FileOutputStream(targetPath.toString())))) { - copyRuntimeJar(outStream, getBallerinaRTJarPath(), copiedEntries); - - JarArchiveEntry e = new JarArchiveEntry(JarFile.MANIFEST_NAME); - outStream.putArchiveEntry(e); - manifest.write(new BufferedOutputStream(outStream)); - outStream.closeArchiveEntry(); - - for (CompiledJarFile compiledJarFile : compiledPackageJarList) { - for (Map.Entry keyVal : compiledJarFile.getJarEntries().entrySet()) { - copyEntry(copiedEntries, outStream, keyVal); - } - } - } - } - - private static void copyEntry(HashSet copiedEntries, - ZipArchiveOutputStream outStream, - Map.Entry keyVal) throws IOException { - String entryName = keyVal.getKey(); - if (!isCopiedOrExcludedEntry(entryName, copiedEntries)) { - byte[] entryContent = keyVal.getValue(); - JarArchiveEntry entry = new JarArchiveEntry(entryName); - outStream.putArchiveEntry(entry); - outStream.write(entryContent); - outStream.closeArchiveEntry(); - } - } - /** * Copies a given jar file into the executable fat jar. * @@ -696,10 +676,10 @@ public static Path createAndGetHomeReposPath() { if (userHomeDir == null || userHomeDir.isEmpty()) { throw new BLangCompilerException("Error creating home repository: unable to get user home directory"); } - homeRepoPath = Paths.get(userHomeDir, ProjectConstants.HOME_REPO_DEFAULT_DIRNAME); + homeRepoPath = Path.of(userHomeDir, ProjectConstants.HOME_REPO_DEFAULT_DIRNAME); } else { // User has specified the home repo path with env variable. - homeRepoPath = Paths.get(homeRepoDir); + homeRepoPath = Path.of(homeRepoDir); } homeRepoPath = homeRepoPath.toAbsolutePath(); @@ -1137,7 +1117,7 @@ public static boolean isProjectUpdated(Project project) { * @return temporary target path */ public static String getTemporaryTargetPath() { - return Paths.get(System.getProperty("java.io.tmpdir")) + return Path.of(System.getProperty("java.io.tmpdir")) .resolve("ballerina-cache" + System.nanoTime()).toString(); } @@ -1269,7 +1249,7 @@ private static boolean isCorrectPatternPathMatch(Path absolutePath, Path package private static List filterPathStream(Stream pathStream, String combinedPattern) { return pathStream.filter( FileSystems.getDefault().getPathMatcher("glob:" + combinedPattern)::matches) - .collect(Collectors.toList()); + .toList(); } private static String getGlobFormatPattern(String pattern) { @@ -1399,6 +1379,44 @@ public static CompatibleRange getCompatibleRange(SemanticVersion version, Packag return CompatibleRange.LOCK_MAJOR; } + public static Map getAllGeneratedResources(Path generatedResourcesPath) { + Map resourcesMap = new HashMap<>(); + if (Files.isDirectory(generatedResourcesPath)) { + try (DirectoryStream stream = Files.newDirectoryStream( + generatedResourcesPath, Files::isRegularFile)) { + for (Path entry : stream) { + Path entryName = entry.getFileName(); + if (entryName == null) { + continue; + } + String resourcePath = RESOURCE_DIR_NAME + DIR_PATH_SEPARATOR + entryName.toString(); + resourcesMap.put(resourcePath, Files.readAllBytes(entry)); + } + } catch (IOException e) { + throw new ProjectException("An error occurred while reading the cached resources from: " + + generatedResourcesPath, e); + } + } + + return resourcesMap; + } + + public static String getConflictingResourcesMsg(String packageDesc, List conflictingResourceFiles) { + StringBuilder errorMessage = new StringBuilder(); + errorMessage.append("failed due to generated resources conflicting with the " + + "resources in the current package '").append(packageDesc).append("'. Conflicting resource files:"); + if (conflictingResourceFiles != null && !conflictingResourceFiles.isEmpty()) { + for (String file : conflictingResourceFiles) { + errorMessage.append("\n").append(file); + } + } + return errorMessage.toString(); + } + + public static String getResourcesPath() { + return "'" + RESOURCE_DIR_NAME + DIR_PATH_SEPARATOR + + DOT + WILD_CARD + "'"; + } /** * Denote the compatibility range of a given tool version. */ @@ -1420,4 +1438,34 @@ public enum CompatibleRange { */ EXACT } + + // TODO: Remove this with https://github.com/ballerina-platform/ballerina-lang/issues/43212 + // once diagnostic support for project loading stage is added. + public static void addProjectLoadingDiagnostic(String diagnosticMessage) { + projectLoadingDiagnostic = diagnosticMessage; + } + + public static String getProjectLoadingDiagnostic() { + return projectLoadingDiagnostic; + } + + /** + * Checks if there are any services in the default module of the project. + * + * @param pkg package instance + * @return true if there are services in the default module, false otherwise + */ + public static boolean containsDefaultModuleService(Package pkg) { + // Here, we are looking at the services only in the default module, since they are run during a bal run. + // However, we can extend this to look at other services + // (including within dependencies) that get engaged during run. + Module defaultModule = pkg.getDefaultModule(); + for (DocumentId documentId: pkg.getDefaultModule().documentIds()) { + ModulePartNode rootNode = defaultModule.document(documentId).syntaxTree().rootNode(); + if (rootNode.members().stream().anyMatch(member -> member.kind() == SyntaxKind.SERVICE_DECLARATION)) { + return true; + } + } + return false; + } } diff --git a/compiler/ballerina-lang/src/main/java/module-info.java b/compiler/ballerina-lang/src/main/java/module-info.java index b76856e09d11..bf773acd7296 100644 --- a/compiler/ballerina-lang/src/main/java/module-info.java +++ b/compiler/ballerina-lang/src/main/java/module-info.java @@ -1,6 +1,9 @@ module io.ballerina.lang { uses io.ballerina.projects.plugins.CompilerPlugin; uses io.ballerina.projects.buildtools.CodeGeneratorTool; + uses org.ballerinalang.spi.CompilerBackendCodeGenerator; + uses org.ballerinalang.compiler.plugins.CompilerPlugin; + uses org.ballerinalang.spi.EmbeddedExecutor; requires java.compiler; requires com.google.gson; requires java.xml; @@ -14,6 +17,8 @@ requires io.ballerina.toml; requires io.ballerina.central.client; requires io.ballerina.identifier; + requires java.semver; + requires maven.resolver; exports io.ballerina.compiler.api; exports io.ballerina.compiler.api.symbols; exports io.ballerina.compiler.api.symbols.resourcepath; diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/codegen/BallerinaAnnotationProcessor.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/codegen/BallerinaAnnotationProcessor.java index 102382fe0f6c..dd0805b8ddcb 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/codegen/BallerinaAnnotationProcessor.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/codegen/BallerinaAnnotationProcessor.java @@ -53,7 +53,7 @@ */ @SupportedAnnotationTypes({ "org.ballerinalang.annotation.JavaSPIService", "org.ballerinalang.natives.annotations.BallerinaFunction" }) -@SupportedSourceVersion(SourceVersion.RELEASE_11) +@SupportedSourceVersion(SourceVersion.RELEASE_17) @SupportedOptions({ "nativeEntityProviderPackage", "nativeEntityProviderClass" }) public class BallerinaAnnotationProcessor extends AbstractProcessor { @@ -206,19 +206,11 @@ private void processJavaSPIServices(RoundEnvironment roundEnv) { private void createServiceFile(String interfaceName, List implClasses) { Filer filer = this.processingEnv.getFiler(); - Writer writer = null; - try { - writer = filer.createResource(StandardLocation.CLASS_OUTPUT, "", JAVA_SPI_SERVICES_BASE_PATH + - interfaceName).openWriter(); + try (Writer writer = filer.createResource(StandardLocation.CLASS_OUTPUT, "", JAVA_SPI_SERVICES_BASE_PATH + + interfaceName).openWriter()) { writer.write(String.join("\n", implClasses)); } catch (IOException e) { throw new RuntimeException("Error creating Java SPI services file: " + e.getMessage(), e); - } finally { - if (writer != null) { - try { - writer.close(); - } catch (IOException ignore) { } - } } } @@ -262,7 +254,7 @@ private interface NativeElementCodeDef { /** * @since 0.94 */ - private class NativeFunctionCodeDef implements NativeElementCodeDef { + private static class NativeFunctionCodeDef implements NativeElementCodeDef { public String org; @@ -286,6 +278,7 @@ protected String typeArrayToCode(List types) { return "new TypeKind[] { " + String.join(", ", vals) + " }"; } + @Override public String code() { return "registerNativeFunction(new NativeFunctionDef(\"" + this.org + "\", \"" + this.pkg + "\", \"" + this.version + "\", \"" + this.name + "\", " + this.typeArrayToCode(this.argTypes) + ", " + @@ -297,10 +290,11 @@ public String code() { /** * @since 0.94 */ - private class NativeActionCodeDef extends NativeFunctionCodeDef { + private static class NativeActionCodeDef extends NativeFunctionCodeDef { public String connectorName; + @Override public String code() { return "registerNativeAction(new NativeActionDef(\"" + this.org + "\", \"" + this.pkg + "\", \"" + this.version + "\", \"" + this.connectorName + "\", \"" diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/compiler/CompilerPhase.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/compiler/CompilerPhase.java index d7021043f07e..7e850e50a6ae 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/compiler/CompilerPhase.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/compiler/CompilerPhase.java @@ -50,37 +50,26 @@ public enum CompilerPhase { CODE_GEN("codeGen"); - private String value; + private final String value; CompilerPhase(String value) { this.value = value; } public static CompilerPhase fromValue(String value) { - switch (value) { - case "define": - return DEFINE; - case "typeCheck": - return TYPE_CHECK; - case "codeAnalyze": - return CODE_ANALYZE; - case "documentationAnalyze": - return DOCUMENTATION_ANALYZE; - case "constantPropagation": - return CONSTANT_PROPAGATION; - case "compilerPlugin": - return COMPILER_PLUGIN; - case "desugar": - return DESUGAR; - case "codeGen": - return CODE_GEN; - case "birGen": - return BIR_GEN; - case "birEmit": - return BIR_EMIT; - default: - throw new IllegalArgumentException("invalid compiler phase: " + value); - } + return switch (value) { + case "define" -> DEFINE; + case "typeCheck" -> TYPE_CHECK; + case "codeAnalyze" -> CODE_ANALYZE; + case "documentationAnalyze" -> DOCUMENTATION_ANALYZE; + case "constantPropagation" -> CONSTANT_PROPAGATION; + case "compilerPlugin" -> COMPILER_PLUGIN; + case "desugar" -> DESUGAR; + case "codeGen" -> CODE_GEN; + case "birGen" -> BIR_GEN; + case "birEmit" -> BIR_EMIT; + default -> throw new IllegalArgumentException("invalid compiler phase: " + value); + }; } @Override diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/compiler/plugins/AbstractCompilerPlugin.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/compiler/plugins/AbstractCompilerPlugin.java index dc1990aec67a..7c579a66f69f 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/compiler/plugins/AbstractCompilerPlugin.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/compiler/plugins/AbstractCompilerPlugin.java @@ -40,6 +40,7 @@ */ public abstract class AbstractCompilerPlugin implements CompilerPlugin { + @Override public abstract void init(DiagnosticLog diagnosticLog); @Override diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/TreeBuilder.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/TreeBuilder.java index 68b530b7b2ac..7e269184fa01 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/TreeBuilder.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/TreeBuilder.java @@ -386,7 +386,10 @@ * * @since 0.94 */ -public class TreeBuilder { +public final class TreeBuilder { + + private TreeBuilder() { + } public static CompilationUnitNode createCompilationUnit() { return new BLangCompilationUnit(); @@ -612,7 +615,7 @@ public static FieldBasedAccessNode createFieldBasedAccessNode() { } public static FieldBasedAccessNode createFieldBasedAccessWithPrefixNode() { - return new BLangFieldBasedAccess.BLangNSPrefixedFieldBasedAccess(); + return new BLangFieldBasedAccess.BLangPrefixedFieldBasedAccess(); } public static TableKeySpecifierNode createTableKeySpecifierNode() { diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/TreeUtils.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/TreeUtils.java index c02bf05e5a19..4984e7099f09 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/TreeUtils.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/TreeUtils.java @@ -25,38 +25,41 @@ /** * This contains model tree related utility functions. */ -public class TreeUtils { - - private static Map stringTypeKindMap = new HashMap<>(); +public final class TreeUtils { + + private static final Map STRING_TYPE_KIND_MAP = new HashMap<>(); static { - stringTypeKindMap.put("int", TypeKind.INT); - stringTypeKindMap.put("byte", TypeKind.BYTE); - stringTypeKindMap.put("float", TypeKind.FLOAT); - stringTypeKindMap.put("decimal", TypeKind.DECIMAL); - stringTypeKindMap.put("boolean", TypeKind.BOOLEAN); - stringTypeKindMap.put("string", TypeKind.STRING); - stringTypeKindMap.put("json", TypeKind.JSON); - stringTypeKindMap.put("xml", TypeKind.XML); - stringTypeKindMap.put("stream", TypeKind.STREAM); - stringTypeKindMap.put("table", TypeKind.TABLE); - stringTypeKindMap.put("any", TypeKind.ANY); - stringTypeKindMap.put("anydata", TypeKind.ANYDATA); - stringTypeKindMap.put("map", TypeKind.MAP); - stringTypeKindMap.put("future", TypeKind.FUTURE); - stringTypeKindMap.put("typedesc", TypeKind.TYPEDESC); - stringTypeKindMap.put("error", TypeKind.ERROR); - stringTypeKindMap.put("()", TypeKind.NIL); - stringTypeKindMap.put("null", TypeKind.NIL); - stringTypeKindMap.put("never", TypeKind.NEVER); - stringTypeKindMap.put("channel", TypeKind.CHANNEL); - stringTypeKindMap.put("service", TypeKind.SERVICE); - stringTypeKindMap.put("handle", TypeKind.HANDLE); - stringTypeKindMap.put("readonly", TypeKind.READONLY); + STRING_TYPE_KIND_MAP.put("int", TypeKind.INT); + STRING_TYPE_KIND_MAP.put("byte", TypeKind.BYTE); + STRING_TYPE_KIND_MAP.put("float", TypeKind.FLOAT); + STRING_TYPE_KIND_MAP.put("decimal", TypeKind.DECIMAL); + STRING_TYPE_KIND_MAP.put("boolean", TypeKind.BOOLEAN); + STRING_TYPE_KIND_MAP.put("string", TypeKind.STRING); + STRING_TYPE_KIND_MAP.put("json", TypeKind.JSON); + STRING_TYPE_KIND_MAP.put("xml", TypeKind.XML); + STRING_TYPE_KIND_MAP.put("stream", TypeKind.STREAM); + STRING_TYPE_KIND_MAP.put("table", TypeKind.TABLE); + STRING_TYPE_KIND_MAP.put("any", TypeKind.ANY); + STRING_TYPE_KIND_MAP.put("anydata", TypeKind.ANYDATA); + STRING_TYPE_KIND_MAP.put("map", TypeKind.MAP); + STRING_TYPE_KIND_MAP.put("future", TypeKind.FUTURE); + STRING_TYPE_KIND_MAP.put("typedesc", TypeKind.TYPEDESC); + STRING_TYPE_KIND_MAP.put("error", TypeKind.ERROR); + STRING_TYPE_KIND_MAP.put("()", TypeKind.NIL); + STRING_TYPE_KIND_MAP.put("null", TypeKind.NIL); + STRING_TYPE_KIND_MAP.put("never", TypeKind.NEVER); + STRING_TYPE_KIND_MAP.put("channel", TypeKind.CHANNEL); + STRING_TYPE_KIND_MAP.put("service", TypeKind.SERVICE); + STRING_TYPE_KIND_MAP.put("handle", TypeKind.HANDLE); + STRING_TYPE_KIND_MAP.put("readonly", TypeKind.READONLY); + } + + private TreeUtils() { } public static TypeKind stringToTypeKind(String typeName) { - return stringTypeKindMap.get(typeName); + return STRING_TYPE_KIND_MAP.get(typeName); } } diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/elements/AttachPoint.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/elements/AttachPoint.java index d4eed83cc3d2..7a891256c294 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/elements/AttachPoint.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/elements/AttachPoint.java @@ -106,7 +106,7 @@ public enum Point { */ CLASS("class"); - private String value; + private final String value; Point(String value) { this.value = value; diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/elements/PackageID.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/elements/PackageID.java index f33bc65873cc..3c2f49be0890 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/elements/PackageID.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/elements/PackageID.java @@ -166,7 +166,7 @@ private List createNameComps(Name name) { if (name == Names.DEFAULT_PACKAGE) { return Lists.of(Names.DEFAULT_PACKAGE); } - return Arrays.stream(name.value.split("\\.")).map(Name::new).collect(Collectors.toList()); + return Arrays.stream(name.value.split("\\.")).map(Name::new).toList(); } /** diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/symbols/SymbolOrigin.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/symbols/SymbolOrigin.java index 838e288f0c4a..22123b431ac7 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/symbols/SymbolOrigin.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/symbols/SymbolOrigin.java @@ -110,17 +110,12 @@ public byte value() { * @return The corresponding enum value if there's a corresponding value. If not, an exception is thrown. */ public static SymbolOrigin toOrigin(byte value) { - switch (value) { - case 1: - return BUILTIN; - case 2: - return SOURCE; - case 3: - return COMPILED_SOURCE; - case 4: - return VIRTUAL; - default: - throw new IllegalStateException("Invalid symbol origin value: " + value); - } + return switch (value) { + case 1 -> BUILTIN; + case 2 -> SOURCE; + case 3 -> COMPILED_SOURCE; + case 4 -> VIRTUAL; + default -> throw new IllegalStateException("Invalid symbol origin value: " + value); + }; } } diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/DocumentationReferenceType.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/DocumentationReferenceType.java index 186bef02e220..d7d318952e0e 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/DocumentationReferenceType.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/DocumentationReferenceType.java @@ -35,7 +35,7 @@ public enum DocumentationReferenceType { PARAMETER("parameter"), // Match for parameter in documentation BACKTICK_CONTENT("function"); // This content is extracted from only backticks. Hence should validate for a function - private String value; + private final String value; DocumentationReferenceType(String value) { this.value = value; diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/NodeKind.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/NodeKind.java index 989e0d1edc7c..1b6c3289d9fa 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/NodeKind.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/NodeKind.java @@ -112,6 +112,10 @@ public enum NodeKind { XML_ELEMENT_FILTER_EXPR, XML_ELEMENT_ACCESS, XML_NAVIGATION, + XML_EXTENDED_NAVIGATION, + XML_STEP_INDEXED_EXTEND, + XML_STEP_FILTER_EXTEND, + XML_STEP_METHOD_CALL_EXTEND, STATEMENT_EXPRESSION, MATCH_EXPRESSION, MATCH_EXPRESSION_PATTERN_CLAUSE, diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/expressions/XMLNavigationAccess.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/expressions/XMLNavigationAccess.java index 9e1ac67d5b15..806bdf718147 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/expressions/XMLNavigationAccess.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/tree/expressions/XMLNavigationAccess.java @@ -50,16 +50,12 @@ enum NavAccessType { } public static NavAccessType fromInt(int number) { - switch (number) { - case 0: - return CHILD_ELEMS; - case 1: - return CHILDREN; - case 2: - return DESCENDANTS; - default: - throw new IllegalArgumentException(); - } + return switch (number) { + case 0 -> CHILD_ELEMS; + case 1 -> CHILDREN; + case 2 -> DESCENDANTS; + default -> throw new IllegalArgumentException(); + }; } } @@ -69,6 +65,4 @@ public static NavAccessType fromInt(int number) { List getFilters(); BLangExpression getExpression(); - - BLangExpression getChildIndex(); } diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/types/TypeKind.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/types/TypeKind.java index 6840c69f241b..885d6c7fa954 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/types/TypeKind.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/model/types/TypeKind.java @@ -95,7 +95,7 @@ public enum TypeKind { REGEXP("regexp") ; - private String name; + private final String name; TypeKind(String name) { this.name = name; diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/natives/NativeElementRepository.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/natives/NativeElementRepository.java index 813e654eb227..25ca1197faab 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/natives/NativeElementRepository.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/natives/NativeElementRepository.java @@ -30,9 +30,9 @@ @Deprecated public class NativeElementRepository { - private Map nativeFuncEntries = new HashMap<>(); + private final Map nativeFuncEntries = new HashMap<>(); - private Map nativeActionEntries = new HashMap<>(); + private final Map nativeActionEntries = new HashMap<>(); private static final String ORG_NAME_SEPARATOR = "/"; @@ -69,19 +69,19 @@ public NativeActionDef lookupNativeAction(String pkgName, String connectorName, */ public static class NativeFunctionDef { - private String orgName; + private final String orgName; - private String pkgName; + private final String pkgName; - private String version; + private final String version; - private String callableName; + private final String callableName; - private String className; + private final String className; - private TypeKind[] argTypes; + private final TypeKind[] argTypes; - private TypeKind[] retTypes; + private final TypeKind[] retTypes; public NativeFunctionDef(String orgName, String pkgName, String version, String callableName, TypeKind[] argTypes, @@ -128,7 +128,7 @@ public TypeKind[] getRetTypes() { */ public static class NativeActionDef extends NativeFunctionDef { - private String connectorName; + private final String connectorName; public NativeActionDef(String orgName, String pkgName, String version, String connectorName, String actionDef, TypeKind[] argTypes, TypeKind[] retTypes, String className) { diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/AggregatedPackageRepository.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/AggregatedPackageRepository.java index ef865af7b55e..51c8f4f76572 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/AggregatedPackageRepository.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/AggregatedPackageRepository.java @@ -34,7 +34,7 @@ */ public class AggregatedPackageRepository implements PackageRepository { - private List repos = new ArrayList<>(); + private final List repos = new ArrayList<>(); public void addRepository(PackageRepository repo) { this.repos.add(repo); diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/CompilerOutputEntry.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/CompilerOutputEntry.java index 45975ceba205..391e9471706e 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/CompilerOutputEntry.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/CompilerOutputEntry.java @@ -17,7 +17,6 @@ */ package org.ballerinalang.repository; -import java.io.IOException; import java.io.InputStream; /** @@ -38,7 +37,7 @@ enum Kind { OBJ("obj"), ROOT("/"); - private String value; + private final String value; Kind(String value) { this.value = value; @@ -67,7 +66,6 @@ public String getValue() { * Returns the content as an input stream. * * @return the {@link InputStream} of the entry - * @throws IOException if input is not resolved */ - InputStream getInputStream() throws IOException; + InputStream getInputStream(); } diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/CompositePackageRepository.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/CompositePackageRepository.java index c620e3498119..3728e41755fc 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/CompositePackageRepository.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/CompositePackageRepository.java @@ -29,7 +29,7 @@ */ public class CompositePackageRepository extends HierarchicalPackageRepository { - private PackageRepository myRepo; + private final PackageRepository myRepo; public CompositePackageRepository(PackageRepository systemRepo, PackageRepository parentRepo, PackageRepository myRepo) { diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/HierarchicalPackageRepository.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/HierarchicalPackageRepository.java index bbdc46b35fd0..57fe121e415a 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/HierarchicalPackageRepository.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/HierarchicalPackageRepository.java @@ -33,9 +33,9 @@ public abstract class HierarchicalPackageRepository implements PackageRepository private static final String BALLERINA_SYSTEM_PKG_PREFIX = "ballerina"; - private PackageRepository systemRepo; + private final PackageRepository systemRepo; - private PackageRepository parentRepo; + private final PackageRepository parentRepo; private Set cachedPackageIds; diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/PackageSource.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/PackageSource.java index 7438bfdaf9df..44a613423b53 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/PackageSource.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/PackageSource.java @@ -49,6 +49,6 @@ public interface PackageSource extends PackageEntity { * * @return the package source entries iterator */ - List getPackageSourceEntries(); + List getPackageSourceEntries(); } diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/fs/ClasspathPackageRepository.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/fs/ClasspathPackageRepository.java index 4002fe988c8e..5f7bf1e27f6f 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/fs/ClasspathPackageRepository.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/fs/ClasspathPackageRepository.java @@ -27,7 +27,6 @@ import java.nio.file.FileSystemAlreadyExistsException; import java.nio.file.FileSystems; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; @@ -65,12 +64,13 @@ private static Path generatePath(Class providerClassRef, Strin pathUri = URI.create("file:" + classPath + basePath); } initFS(pathUri); - return Paths.get(pathUri); + return Path.of(pathUri); } catch (URISyntaxException | IOException e) { throw new RuntimeException(e); } } - + + @SuppressWarnings("resource") private static void initFS(URI uri) throws IOException { if (JAR_URI_SCHEME.equals(uri.getScheme())) { Map env = new HashMap<>(); diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/fs/GeneralFSPackageRepository.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/fs/GeneralFSPackageRepository.java index 4efb7f4ebd12..102347a2794e 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/fs/GeneralFSPackageRepository.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/fs/GeneralFSPackageRepository.java @@ -39,7 +39,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; -import java.util.stream.Collectors; +import java.util.stream.Stream; /** * This represents a general file system based {@link PackageRepository}. @@ -136,7 +136,11 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th return FileVisitResult.SKIP_SUBTREE; } List nameComps = new ArrayList<>(); - if (Files.list(dir).filter(f -> isBALFile(f)).count() > 0) { + boolean balFilesExist; + try (Stream paths = Files.list(dir)) { + balFilesExist = paths.filter(f -> isBALFile(f)).count() > 0; + } + if (balFilesExist) { int dirNameCount = dir.getNameCount(); if (dirNameCount > baseNameCount) { dir.subpath(baseNameCount, dirNameCount).forEach( @@ -233,10 +237,10 @@ public PackageID getPackageId() { @Override public List getEntryNames() { if (this.cachedEntryNames == null) { - try { - List files = Files.walk(this.pkgPath, 1).filter( + try (Stream paths = Files.walk(this.pkgPath, 1)) { + List files = paths.filter( Files::isRegularFile).filter(e -> e.getFileName().toString().endsWith(BAL_SOURCE_EXT)). - collect(Collectors.toList()); + toList(); this.cachedEntryNames = new ArrayList<>(files.size()); files.stream().forEach(e -> this.cachedEntryNames.add(e.getFileName().toString())); } catch (IOException e) { @@ -253,8 +257,8 @@ public CompilerInput getPackageSourceEntry(String name) { } @Override - public List getPackageSourceEntries() { - return this.getEntryNames().stream().map(e -> new FSCompilerInput(e)).collect(Collectors.toList()); + public List getPackageSourceEntries() { + return this.getEntryNames().stream().map(e -> new FSCompilerInput(e)).toList(); } /** @@ -264,11 +268,11 @@ public List getPackageSourceEntries() { */ public class FSCompilerInput implements CompilerInput { - private String name; + private final String name; - private byte[] code; + private final byte[] code; - private SyntaxTree tree; + private final SyntaxTree tree; public FSCompilerInput(String name) { this.name = name; @@ -315,7 +319,7 @@ public String getName() { * * @since 0.94 */ - public class FSPackageEntityNotAvailableException extends Exception { + public static class FSPackageEntityNotAvailableException extends Exception { private static final long serialVersionUID = 1528033476455781589L; diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/fs/LocalFSPackageRepository.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/fs/LocalFSPackageRepository.java index 4d8f7351808a..af295766088f 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/fs/LocalFSPackageRepository.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/repository/fs/LocalFSPackageRepository.java @@ -19,7 +19,7 @@ import org.wso2.ballerinalang.compiler.util.Name; -import java.nio.file.Paths; +import java.nio.file.Path; /** * This represents a local file system based {@link org.ballerinalang.repository.PackageRepository}. @@ -29,10 +29,10 @@ public class LocalFSPackageRepository extends GeneralFSPackageRepository { public LocalFSPackageRepository(String basePath) { - super(Paths.get(basePath)); + super(Path.of(basePath)); } public LocalFSPackageRepository(String basePath, String orgName) { - super(Paths.get(basePath), new Name(orgName)); + super(Path.of(basePath), new Name(orgName)); } } diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/spi/SystemPackageRepositoryProvider.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/spi/SystemPackageRepositoryProvider.java index 4e22d9d300f8..b62fed8f6b4d 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/spi/SystemPackageRepositoryProvider.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/spi/SystemPackageRepositoryProvider.java @@ -22,6 +22,7 @@ import java.net.URI; import java.net.URISyntaxException; +import java.nio.file.Path; /** * This represents the Java SPI interface for a Ballerina system package repository provider. @@ -43,6 +44,6 @@ static URI getClassUri(Object obj) { * * @return the loaded {@link PackageRepository} object */ - Repo loadRepository(); + Repo loadRepository(); } diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/model/Dependency.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/model/Dependency.java index 4d35fd312715..80e7ae5b67ef 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/model/Dependency.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/model/Dependency.java @@ -67,7 +67,7 @@ public void setMetadata(DependencyMetadata metadata) { public String toString() { return null != this.metadata && null != this.metadata.getVersion() && - !"".equals(this.metadata.getVersion().trim()) ? + !this.metadata.getVersion().trim().isEmpty() ? getModuleID() + ":" + this.metadata.getVersion() : getModuleID(); } @@ -76,10 +76,9 @@ public boolean equals(Object o) { if (this == o) { return true; } - if (!(o instanceof Dependency)) { + if (!(o instanceof Dependency that)) { return false; } - Dependency that = (Dependency) o; return this.toString().equals(that.toString()); } diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/model/DependencyMetadata.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/model/DependencyMetadata.java index d7c31817a4de..7069d859b74e 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/model/DependencyMetadata.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/model/DependencyMetadata.java @@ -20,7 +20,6 @@ import org.ballerinalang.toml.util.PathUtils; import java.nio.file.Path; -import java.nio.file.Paths; /** * Defines dependency object fields. The same object will be used to define patches. @@ -58,7 +57,7 @@ public Path getPath() { if (PathUtils.getPath(this.path) == null) { return null; } - return Paths.get(PathUtils.getPath(this.path)); + return Path.of(PathUtils.getPath(this.path)); } /** diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/model/LockFileImport.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/model/LockFileImport.java index 816cc672727b..0193e5e3be49 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/model/LockFileImport.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/model/LockFileImport.java @@ -70,10 +70,9 @@ public boolean equals(Object o) { if (this == o) { return true; } - if (!(o instanceof LockFileImport)) { + if (!(o instanceof LockFileImport that)) { return false; } - LockFileImport that = (LockFileImport) o; return Objects.equals(org_name, that.org_name) && Objects.equals(getName(), that.getName()) && Objects.equals(getVersion(), that.getVersion()); diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/model/Manifest.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/model/Manifest.java index 1f38619eaf28..3e059952d317 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/model/Manifest.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/model/Manifest.java @@ -33,7 +33,7 @@ */ public class Manifest { private Project project = new Project(); - private Map dependencies = new LinkedHashMap<>(); + private final Map dependencies = new LinkedHashMap<>(); public Platform platform = new Platform(); private BuildOptions buildOptions; @@ -59,15 +59,14 @@ public List getDependencies() { dependency.setMetadata(convertObjectToDependencyMetadata(entry.getValue())); return dependency; }) - .collect(Collectors.toList()); + .toList(); } private DependencyMetadata convertObjectToDependencyMetadata(Object obj) { DependencyMetadata metadata = new DependencyMetadata(); - if (obj instanceof String) { - metadata.setVersion((String) obj); - } else if (obj instanceof Map) { - Map metadataMap = (Map) obj; + if (obj instanceof String s) { + metadata.setVersion(s); + } else if (obj instanceof Map metadataMap) { if (metadataMap.keySet().contains("version") && metadataMap.get("version") instanceof String) { metadata.setVersion((String) metadataMap.get("version")); } @@ -105,12 +104,10 @@ public String getTargetPlatform(String moduleName) { "\nSupported platforms : " + supportedPlatforms()); } // Check if module have platform specific libraries - List deps = platform.libraries.stream().filter(library -> { - return library.getModules() == null || - Arrays.stream(library.getModules()).anyMatch(moduleName::equals); - }).collect(Collectors.toList()); + List deps = platform.libraries.stream().filter(library -> library.getModules() == null || + Arrays.stream(library.getModules()).anyMatch(moduleName::equals)).toList(); // If not return any - if (deps.size() > 0) { + if (!deps.isEmpty()) { return platform.target; } } diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/parser/ManifestProcessor.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/parser/ManifestProcessor.java index 3a89216cca04..a96513a560a2 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/parser/ManifestProcessor.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/parser/ManifestProcessor.java @@ -107,11 +107,13 @@ public static Manifest parseTomlContentFromString(String content) throws TomlExc try { Toml toml = new Toml().read(content); if (toml.isEmpty()) { - throw new TomlException("invalid Ballerina.toml file: organization name and the version of the " + - "project is missing. example: \n" + - "[project]\n" + - "org-name=\"my_org\"\n" + - "version=\"1.0.0\"\n"); + throw new TomlException(""" + invalid Ballerina.toml file: organization name and the version of the \ + project is missing. example:\s + [project] + org-name="my_org" + version="1.0.0" + """); } if (null == toml.getTable("project")) { @@ -141,11 +143,13 @@ public static Manifest parseTomlContentAsStream(InputStream inputStream) throws try { Toml toml = new Toml().read(inputStream); if (toml.isEmpty()) { - throw new TomlException("invalid Ballerina.toml file: organization name and the version of the " + - "project is missing. example: \n" + - "[project]\n" + - "org-name=\"my_org\"\n" + - "version=\"1.0.0\"\n"); + throw new TomlException(""" + invalid Ballerina.toml file: organization name and the version of the \ + project is missing. example:\s + [project] + org-name="my_org" + version="1.0.0" + """); } if (null == toml.getTable("project")) { @@ -224,11 +228,11 @@ public static byte[] addDependenciesToManifest(ByteArrayInputStream manifestStre if (toml.containsKey("dependencies")) { Object tomlDepsAsObject = toml.get("dependencies"); Map updatedDependencies = new HashMap<>(); - if (tomlDepsAsObject instanceof HashMap) { + if (tomlDepsAsObject instanceof HashMap tomlDeps) { // taking care of double quoted dependency names - Map tomlDeps = (HashMap) tomlDepsAsObject; - for (Map.Entry dep : tomlDeps.entrySet()) { - updatedDependencies.put(dep.getKey().replaceAll("^\"|\"$", ""), dep.getValue()); + for (Map.Entry dep : tomlDeps.entrySet()) { + updatedDependencies.put( + ((String) dep.getKey()).replaceAll("^\"|\"$", ""), dep.getValue()); } dependencies = updatedDependencies; } diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/util/PathUtils.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/util/PathUtils.java index 95e28f90c063..956e39a6026b 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/util/PathUtils.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/toml/util/PathUtils.java @@ -23,9 +23,13 @@ * This class can be used to handle different path possibilities in the toml for native-libs and dependencies. * */ -public class PathUtils { +public final class PathUtils { + private static final String OS = System.getProperty("os.name").toLowerCase(Locale.getDefault()); + private PathUtils() { + } + public static String getPath(String path) { if (path != null) { if (OS.contains("win")) { diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/BLangCompilerConstants.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/BLangCompilerConstants.java index 58f229cd9574..f9e4dba15afa 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/BLangCompilerConstants.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/BLangCompilerConstants.java @@ -23,7 +23,7 @@ * * @since 1.1.0 */ -public class BLangCompilerConstants { +public final class BLangCompilerConstants { public static final String ITERABLE_COLLECTION_ITERATOR_FUNC = "iterator"; public static final String RETRY_MANAGER_OBJECT_SHOULD_RETRY_FUNC = "shouldRetry"; diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/BackendCodeGeneratorProvider.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/BackendCodeGeneratorProvider.java index 280d7d157a43..625dde89f4ac 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/BackendCodeGeneratorProvider.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/BackendCodeGeneratorProvider.java @@ -29,7 +29,7 @@ */ public class BackendCodeGeneratorProvider { - private static BackendCodeGeneratorProvider provider = new BackendCodeGeneratorProvider(); + private static final BackendCodeGeneratorProvider PROVIDER = new BackendCodeGeneratorProvider(); private final ServiceLoader loader; @@ -46,7 +46,7 @@ private BackendCodeGeneratorProvider() { * @return instance of BackendCodeGeneratorProvider */ public static BackendCodeGeneratorProvider getInstance() { - return provider; + return PROVIDER; } /** diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/BootstrapRunner.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/BootstrapRunner.java index 643612c04ff6..2c69a1cb79a4 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/BootstrapRunner.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/BootstrapRunner.java @@ -40,7 +40,7 @@ /** * Creates jars in file system using bootstrap pack and create class loader hierarchy for them. */ -public class BootstrapRunner { +public final class BootstrapRunner { private static final PrintStream out = System.out; private static final PrintStream err = System.err; @@ -50,6 +50,9 @@ public class BootstrapRunner { private static final String COMPILER_BACKEND_LLVM = "ballerina.compiler_backend_llvm.$_init"; private static String javaCommand = System.getProperty("java.command"); + private BootstrapRunner() { + } + public static void loadTargetAndGenerateJarBinary(String entryBir, String jarOutputPath, boolean dumpBir, HashSet moduleDependencySet, String... birCachePaths) { //Load all Jars from module dependency set. diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/EmbeddedExecutorProvider.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/EmbeddedExecutorProvider.java index 875f804ce085..9b9bf0c36815 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/EmbeddedExecutorProvider.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/EmbeddedExecutorProvider.java @@ -9,7 +9,7 @@ * Ballerina package provider class used in package management. */ public class EmbeddedExecutorProvider { - private static EmbeddedExecutorProvider provider = new EmbeddedExecutorProvider(); + private static final EmbeddedExecutorProvider PROVIDER = new EmbeddedExecutorProvider(); private final ServiceLoader loader; @@ -26,7 +26,7 @@ private EmbeddedExecutorProvider() { * @return instance of EmbeddedExecutorProvider */ public static EmbeddedExecutorProvider getInstance() { - return provider; + return PROVIDER; } /** diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/FunctionFlags.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/FunctionFlags.java index 10bbb5578c92..15421edcd4f0 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/FunctionFlags.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/FunctionFlags.java @@ -20,12 +20,15 @@ /** * This represents the function related flags. The flags are set/get using bit masks. */ -public class FunctionFlags { +public final class FunctionFlags { public static final int NOTHING = 0; public static final int ASYNC = 1; public static final int OBSERVED = ASYNC << 1; + private FunctionFlags() { + } + public static boolean isAsync(int flags) { return (flags & FunctionFlags.ASYNC) == FunctionFlags.ASYNC; } diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/Transactions.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/Transactions.java index 8295ed3911d1..18f1130cb859 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/Transactions.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/Transactions.java @@ -24,11 +24,15 @@ * * @since 0.95.5 */ -public class Transactions { +public final class Transactions { + public static final String TRANSACTION_ANNOTATION_NAME = "transactions" + ORG_NAME_SEPARATOR + "Participant"; public static final String TRX_ONCOMMIT_FUNC = "oncommit"; public static final String TRX_ONABORT_FUNC = "onabort"; + private Transactions() { + } + public static boolean isTransactionsAnnotation(String orgName, String pkgName) { StringBuilder pathBuilder = new StringBuilder(); String createdPath = pathBuilder.append(orgName).append(ORG_NAME_SEPARATOR).append(pkgName).toString(); @@ -63,7 +67,7 @@ public enum TransactionStatus { ABORTED(-2), END(1); - private int status; + private final int status; TransactionStatus(int value) { status = value; @@ -74,18 +78,13 @@ public int value() { } public static TransactionStatus getConst(int statusValue) { - switch (statusValue) { - case 0: - return BLOCK_END; - case 1: - return END; - case -1: - return FAILED; - case -2: - return ABORTED; - default: - throw new IllegalArgumentException(); - } + return switch (statusValue) { + case 0 -> BLOCK_END; + case 1 -> END; + case -1 -> FAILED; + case -2 -> ABORTED; + default -> throw new IllegalArgumentException(); + }; } } } diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticErrorCode.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticErrorCode.java index 85d000657a83..63b9648cd3bd 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticErrorCode.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticErrorCode.java @@ -251,7 +251,6 @@ public enum DiagnosticErrorCode implements DiagnosticCode { INCOMPATIBLE_TYPES_CONVERSION_WITH_SUGGESTION("BCE2503", "incompatible.types.conversion.with.suggestion"), UNSAFE_CAST_ATTEMPT("BCE2504", "unsafe.cast.attempt"), - INVALID_LITERAL_FOR_TYPE("BCE2506", "invalid.literal.for.type"), INCOMPATIBLE_MAPPING_CONSTRUCTOR("BCE2507", "incompatible.mapping.constructor.expression"), MAPPING_CONSTRUCTOR_COMPATIBLE_TYPE_NOT_FOUND("BCE2508", "mapping.constructor.compatible.type.not.found"), CANNOT_INFER_TYPES_FOR_TUPLE_BINDING("BCE2509", "cannot.infer.types.for.tuple.binding"), @@ -333,7 +332,6 @@ public enum DiagnosticErrorCode implements DiagnosticCode { INVALID_ANY_VAR_DEF("BCE2574", "invalid.any.var.def"), INVALID_RECORD_LITERAL("BCE2575", "invalid.record.literal"), INVALID_FIELD_IN_RECORD_BINDING_PATTERN("BCE2576", "invalid.field.in.record.binding.pattern"), - INVALID_RECORD_LITERAL_BINDING_PATTERN("BCE2577", "invalid.record.literal.in.binding.pattern"), DUPLICATE_KEY_IN_MAPPING_CONSTRUCTOR("BCE2578", "duplicate.key.in.mapping.constructor"), DUPLICATE_KEY_IN_TABLE_LITERAL("BCE2579", "duplicate.key.in.table.literal"), DUPLICATE_KEY_IN_RECORD_LITERAL_SPREAD_OP("BCE2580", "duplicate.key.in.record.literal.spread.op"), @@ -389,7 +387,7 @@ public enum DiagnosticErrorCode implements DiagnosticCode { INVALID_NAMESPACE_DECLARATION("BCE2624", "invalid.namespace.declaration"), CANNOT_UPDATE_XML_SEQUENCE("BCE2625", "cannot.update.xml.sequence"), INVALID_XML_NS_INTERPOLATION("BCE2626", "invalid.xml.ns.interpolation"), - CANNOT_FIND_XML_NAMESPACE("BCE2627", "cannot.find.xml.namespace.prefix"), + CANNOT_FIND_XML_NAMESPACE("BCE2627", "cannot.find.xml.prefix"), UNSUPPORTED_METHOD_INVOCATION_XML_NAV("BCE2628", "method.invocation.in.xml.navigation.expressions.not.supported"), DEPRECATED_XML_ATTRIBUTE_ACCESS("BCE2629", "deprecated.xml.attribute.access.expression"), UNSUPPORTED_MEMBER_ACCESS_IN_XML_NAVIGATION("BCE2630", @@ -426,6 +424,7 @@ public enum DiagnosticErrorCode implements DiagnosticCode { "invalid.field.binding.pattern.with.non.required.field"), INFER_SIZE_ONLY_SUPPORTED_IN_FIRST_DIMENSION("BCE2654", "infer.size.only.supported.in.the.first.dimension"), FUNCTION_CALL_SYNTAX_NOT_DEFINED("BCE2655", "function.call.syntax.not.defined"), + UNDEFINED_CONSTANT_SYMBOL("BCE2656", "undefined.constant.symbol"), // Error codes related to iteration. ITERABLE_NOT_SUPPORTED_COLLECTION("BCE2800", "iterable.not.supported.collection"), @@ -733,7 +732,6 @@ public enum DiagnosticErrorCode implements DiagnosticCode { CONTINUE_NOT_ALLOWED("BCE3992", "continue.not.allowed"), BREAK_NOT_ALLOWED("BCE3993", "break.not.allowed"), - XML_FUNCTION_DOES_NOT_SUPPORT_ARGUMENT_TYPE("BCE3995", "xml.function.does.not.support.argument.type"), INTERSECTION_NOT_ALLOWED_WITH_TYPE("BCE3996", "intersection.not.allowed.with.type"), ASYNC_SEND_NOT_YET_SUPPORTED_AS_EXPRESSION("BCE3997", "async.send.action.not.yet.supported.as.expression"), @@ -819,10 +817,11 @@ public enum DiagnosticErrorCode implements DiagnosticCode { EXPRESSION_OF_FUTURE_TYPE_EXPECTED("BCE4057", "future.expression.expected"), INSTANTIATION_ERROR("BCE4058", "instantiation.error"), INVALID_BINDING_PATTERN_IN_ON_FAIL("BCE4059", "invalid.binding.pattern.in.on.fail"), + INVALID_USAGE_OF_CHECK_IN_PARAMETER_DEFAULT("BCE4060", "invalid.usage.of.check.in.parameter.default") ; - private String diagnosticId; - private String messageKey; + private final String diagnosticId; + private final String messageKey; DiagnosticErrorCode(String diagnosticId, String messageKey) { this.diagnosticId = diagnosticId; diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticHintCode.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticHintCode.java index 4f2f028189e7..19c122cb1396 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticHintCode.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticHintCode.java @@ -38,8 +38,8 @@ public enum DiagnosticHintCode implements DiagnosticCode { CONCURRENT_CALLS_WILL_NOT_BE_MADE_TO_NON_ISOLATED_METHOD( "BCH2005", "concurrent.calls.will.not.be.made.to.non.isolated.method"),; - private String diagnosticId; - private String messageKey; + private final String diagnosticId; + private final String messageKey; DiagnosticHintCode(String diagnosticId, String messageKey) { this.diagnosticId = diagnosticId; diff --git a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticWarningCode.java b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticWarningCode.java index 7c4963332136..a3ed3b3e408a 100644 --- a/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticWarningCode.java +++ b/compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticWarningCode.java @@ -72,8 +72,8 @@ public enum DiagnosticWarningCode implements DiagnosticCode { USAGE_OF_STRAND_ANNOTATION_WILL_BE_DEPRECATED("BCE20406", "strand.annotation.will.be.deprecated"), ; - private String diagnosticId; - private String messageKey; + private final String diagnosticId; + private final String messageKey; DiagnosticWarningCode(String diagnosticId, String messageKey) { this.diagnosticId = diagnosticId; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/BIRPackageSymbolEnter.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/BIRPackageSymbolEnter.java index b359c35fafb2..0dd00444e14f 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/BIRPackageSymbolEnter.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/BIRPackageSymbolEnter.java @@ -128,7 +128,6 @@ /** * This class is responsible for reading the compiled package file (bir) and creating a package symbol. - *

* * @since 0.995.0 */ @@ -144,14 +143,14 @@ public class BIRPackageSymbolEnter { private BIRPackageSymbolEnv env; private List structureTypes; // TODO find a better way private BStructureTypeSymbol currentStructure = null; - private LinkedList compositeStack = new LinkedList<>(); + private final LinkedList compositeStack = new LinkedList<>(); private static final int SERVICE_TYPE_TAG = 54; private static final CompilerContext.Key COMPILED_PACKAGE_SYMBOL_ENTER_KEY = new CompilerContext.Key<>(); - private Map globalVarMap = new HashMap<>(); + private final Map globalVarMap = new HashMap<>(); public static BIRPackageSymbolEnter getInstance(CompilerContext context) { BIRPackageSymbolEnter packageReader = context.get(COMPILED_PACKAGE_SYMBOL_ENTER_KEY); @@ -285,7 +284,7 @@ private void populateReferencedFunctions() { continue; } String referencedFuncName = function.funcName.value; - Name funcName = names.fromString( + Name funcName = Names.fromString( Symbols.getAttachedFuncSymbolName(structureTypeSymbol.name.value, referencedFuncName)); Scope.ScopeEntry matchingObjFuncSym = objectType.tsymbol.scope.lookup(funcName); if (matchingObjFuncSym == NOT_FOUND_ENTRY) { @@ -398,12 +397,12 @@ private void defineFunction(DataInputStream dataInStream) throws IOException { String funcName = getStringCPEntryValue(dataInStream); String funcOrigName = getStringCPEntryValue(dataInStream); String workerName = getStringCPEntryValue(dataInStream); - var flags = dataInStream.readLong(); + long flags = dataInStream.readLong(); byte origin = dataInStream.readByte(); BInvokableType funcType = (BInvokableType) readBType(dataInStream); BInvokableSymbol invokableSymbol = - Symbols.createFunctionSymbol(flags, names.fromString(funcName), names.fromString(funcOrigName), + Symbols.createFunctionSymbol(flags, Names.fromString(funcName), Names.fromString(funcOrigName), this.env.pkgSymbol.pkgID, funcType, this.env.pkgSymbol, Symbols.isFlagOn(flags, Flags.NATIVE), pos, toOrigin(origin)); invokableSymbol.source = pos.lineRange().fileName(); @@ -419,14 +418,14 @@ private void defineFunction(DataInputStream dataInStream) throws IOException { // Update the symbol invokableSymbol.owner = attachedType.tsymbol; invokableSymbol.name = - names.fromString(Symbols.getAttachedFuncSymbolName(attachedType.tsymbol.name.value, funcName)); + Names.fromString(Symbols.getAttachedFuncSymbolName(attachedType.tsymbol.name.value, funcName)); if (attachedType.tag == TypeTags.OBJECT || attachedType.tag == TypeTags.RECORD) { scopeToDefine = attachedType.tsymbol.scope; if (isResourceFunction) { int pathParamCount = dataInStream.readInt(); List pathParams = new ArrayList<>(pathParamCount); for (int i = 0; i < pathParamCount; i++) { - Name pathParamName = names.fromString(getStringCPEntryValue(dataInStream)); + Name pathParamName = Names.fromString(getStringCPEntryValue(dataInStream)); BType paramType = readBType(dataInStream); BVarSymbol varSymbol = new BVarSymbol(0, pathParamName, this.env.pkgSymbol.pkgID, paramType, null, symTable.builtinPos, COMPILED_SOURCE); @@ -436,7 +435,7 @@ private void defineFunction(DataInputStream dataInStream) throws IOException { boolean restPathParamExist = dataInStream.readBoolean(); BVarSymbol restPathParam = null; if (restPathParamExist) { - Name pathParamName = names.fromString(getStringCPEntryValue(dataInStream)); + Name pathParamName = Names.fromString(getStringCPEntryValue(dataInStream)); BType paramType = readBType(dataInStream); restPathParam = new BVarSymbol(0, pathParamName, this.env.pkgSymbol.pkgID, paramType, null, symTable.builtinPos, COMPILED_SOURCE); @@ -447,14 +446,14 @@ private void defineFunction(DataInputStream dataInStream) throws IOException { List resourcePathSegmentPosList = new ArrayList<>(resourcePathCount); List pathSegmentTypeList = new ArrayList<>(resourcePathCount); for (int i = 0; i < resourcePathCount; i++) { - resourcePath.add(names.fromString(getStringCPEntryValue(dataInStream))); + resourcePath.add(Names.fromString(getStringCPEntryValue(dataInStream))); resourcePathSegmentPosList.add(readPosition(dataInStream)); pathSegmentTypeList.add(readBType(dataInStream)); } - Name accessor = names.fromString(getStringCPEntryValue(dataInStream)); + Name accessor = Names.fromString(getStringCPEntryValue(dataInStream)); - BResourceFunction resourceFunction = new BResourceFunction(names.fromString(funcName), + BResourceFunction resourceFunction = new BResourceFunction(Names.fromString(funcName), invokableSymbol, funcType, accessor, pathParams, restPathParam, symTable.builtinPos); // If it is a resource function, attached type should be an object @@ -478,7 +477,7 @@ private void defineFunction(DataInputStream dataInStream) throws IOException { objectTypeSymbol.attachedFuncs.add(resourceFunction); } else { BAttachedFunction attachedFunc = - new BAttachedFunction(names.fromString(funcName), invokableSymbol, funcType, + new BAttachedFunction(Names.fromString(funcName), invokableSymbol, funcType, symTable.builtinPos); BStructureTypeSymbol structureTypeSymbol = (BStructureTypeSymbol) attachedType.tsymbol; if (Names.USER_DEFINED_INIT_SUFFIX.value.equals(funcName) || @@ -534,7 +533,7 @@ private void defineTypeDef(DataInputStream dataInStream) throws IOException { String typeDefName = getStringCPEntryValue(dataInStream); String typeDefOrigName = getStringCPEntryValue(dataInStream); - var flags = dataInStream.readLong(); + long flags = dataInStream.readLong(); byte origin = dataInStream.readByte(); byte[] docBytes = readDocBytes(dataInStream); @@ -549,7 +548,7 @@ private void defineTypeDef(DataInputStream dataInStream) throws IOException { referenceType = (BTypeReferenceType) type; referenceType.tsymbol.pos = pos; } else { - BTypeSymbol typeSymbol = new BTypeSymbol(SymTag.TYPE_REF, flags, names.fromString(typeDefName), + BTypeSymbol typeSymbol = new BTypeSymbol(SymTag.TYPE_REF, flags, Names.fromString(typeDefName), this.env.pkgSymbol.pkgID, type, this.env.pkgSymbol, pos, COMPILED_SOURCE); referenceType = new BTypeReferenceType(type, typeSymbol, flags); } @@ -572,11 +571,11 @@ private void defineTypeDef(DataInputStream dataInStream) throws IOException { symbol = type.tsymbol; symbol.pos = pos; } else { - symbol = Symbols.createTypeDefinitionSymbol(flags, names.fromString(typeDefName), + symbol = Symbols.createTypeDefinitionSymbol(flags, Names.fromString(typeDefName), this.env.pkgSymbol.pkgID, type, this.env.pkgSymbol, pos, COMPILED_SOURCE); ((BTypeDefinitionSymbol) symbol).referenceType = referenceType; } - symbol.originalName = names.fromString(typeDefOrigName); + symbol.originalName = Names.fromString(typeDefOrigName); symbol.origin = toOrigin(origin); symbol.flags = flags; @@ -694,7 +693,7 @@ private BAnnotationSymbol defineAnnotation(DataInputStream dataInStream) throws String name = getStringCPEntryValue(dataInStream); String originalName = getStringCPEntryValue(dataInStream); - var flags = dataInStream.readLong(); + long flags = dataInStream.readLong(); byte origin = dataInStream.readByte(); Location pos = readPosition(dataInStream); @@ -710,8 +709,8 @@ private BAnnotationSymbol defineAnnotation(DataInputStream dataInStream) throws BPackageSymbol pkgSymbol = pkgId.equals(env.pkgSymbol.pkgID) ? this.env.pkgSymbol : packageCache.getSymbol(pkgId); - BAnnotationSymbol annotationSymbol = Symbols.createAnnotationSymbol(flags, attachPoints, names.fromString(name), - names.fromString(originalName), + BAnnotationSymbol annotationSymbol = Symbols.createAnnotationSymbol(flags, attachPoints, Names.fromString(name), + Names.fromString(originalName), pkgId, null, pkgSymbol, pos, toOrigin(origin)); annotationSymbol.type = new BAnnotationType(annotationSymbol); @@ -752,7 +751,7 @@ private BAnnotationAttachmentSymbol defineAnnotationAttachmentSymbol(DataInputSt private void defineConstant(DataInputStream dataInStream) throws IOException { String constantName = getStringCPEntryValue(dataInStream); - var flags = dataInStream.readLong(); + long flags = dataInStream.readLong(); byte origin = dataInStream.readByte(); Location pos = readPosition(dataInStream); @@ -762,7 +761,7 @@ private void defineConstant(DataInputStream dataInStream) throws IOException { Scope enclScope = this.env.pkgSymbol.scope; // Create the constant symbol. - BConstantSymbol constantSymbol = new BConstantSymbol(flags, names.fromString(constantName), + BConstantSymbol constantSymbol = new BConstantSymbol(flags, Names.fromString(constantName), this.env.pkgSymbol.pkgID, null, type, enclScope.owner, pos, toOrigin(origin)); @@ -851,9 +850,9 @@ private void defineServiceDeclarations(DataInputStream inputStream) throws IOExc attachPointLiteral = getStringCPEntryValue(inputStream); } - BSymbol classSymbol = this.env.pkgSymbol.scope.lookup(names.fromString(associatedClassName)).symbol; + BSymbol classSymbol = this.env.pkgSymbol.scope.lookup(Names.fromString(associatedClassName)).symbol; BServiceSymbol serviceDecl = new BServiceSymbol((BClassSymbol) classSymbol, flags, - names.fromString(serviceName), this.env.pkgSymbol.pkgID, type, + Names.fromString(serviceName), this.env.pkgSymbol.pkgID, type, this.env.pkgSymbol, pos, SymbolOrigin.toOrigin(origin)); int nListeners = inputStream.readInt(); @@ -863,14 +862,14 @@ private void defineServiceDeclarations(DataInputStream inputStream) throws IOExc serviceDecl.setAttachPointStringLiteral(attachPointLiteral); serviceDecl.setAbsResourcePath(attachPoint); - this.env.pkgSymbol.scope.define(names.fromString(serviceName), serviceDecl); + this.env.pkgSymbol.scope.define(Names.fromString(serviceName), serviceDecl); } private void definePackageLevelVariables(DataInputStream dataInStream) throws IOException { Location pos = readPosition(dataInStream); dataInStream.readByte(); // Read and ignore the kind as it is anyway global variable String varName = getStringCPEntryValue(dataInStream); - var flags = dataInStream.readLong(); + long flags = dataInStream.readLong(); byte origin = dataInStream.readByte(); byte[] docBytes = readDocBytes(dataInStream); @@ -882,7 +881,7 @@ private void definePackageLevelVariables(DataInputStream dataInStream) throws IO BVarSymbol varSymbol; if (referredVarType.tag == TypeTags.INVOKABLE) { BInvokableTypeSymbol bInvokableTypeSymbol = (BInvokableTypeSymbol) referredVarType.tsymbol; - BInvokableSymbol invokableSymbol = new BInvokableSymbol(SymTag.VARIABLE, flags, names.fromString(varName), + BInvokableSymbol invokableSymbol = new BInvokableSymbol(SymTag.VARIABLE, flags, Names.fromString(varName), this.env.pkgSymbol.pkgID, referredVarType, enclScope.owner, symTable.builtinPos, toOrigin(origin)); invokableSymbol.kind = SymbolKind.FUNCTION; @@ -893,7 +892,7 @@ private void definePackageLevelVariables(DataInputStream dataInStream) throws IO invokableSymbol.retType = ((BInvokableType) invokableSymbol.type).retType; varSymbol = invokableSymbol; } else { - varSymbol = new BVarSymbol(flags, names.fromString(varName), this.env.pkgSymbol.pkgID, varType, + varSymbol = new BVarSymbol(flags, Names.fromString(varName), this.env.pkgSymbol.pkgID, varType, enclScope.owner, symTable.builtinPos, toOrigin(origin)); if (varType.tsymbol != null && Symbols.isFlagOn(varType.tsymbol.flags, Flags.CLIENT)) { varSymbol.tag = SymTag.ENDPOINT; @@ -917,8 +916,8 @@ private void setParamSymbols(BInvokableSymbol invokableSymbol, DataInputStream d BInvokableType invokableType = (BInvokableType) invokableSymbol.type; for (int i = 0; i < requiredParamCount; i++) { String paramName = getStringCPEntryValue(dataInStream); - var flags = dataInStream.readLong(); - BVarSymbol varSymbol = new BVarSymbol(flags, names.fromString(paramName), this.env.pkgSymbol.pkgID, + long flags = dataInStream.readLong(); + BVarSymbol varSymbol = new BVarSymbol(flags, Names.fromString(paramName), this.env.pkgSymbol.pkgID, invokableType.paramTypes.get(i), invokableSymbol, symTable.builtinPos, COMPILED_SOURCE); varSymbol.isDefaultable = ((flags & Flags.OPTIONAL) == Flags.OPTIONAL); @@ -928,7 +927,7 @@ private void setParamSymbols(BInvokableSymbol invokableSymbol, DataInputStream d if (dataInStream.readBoolean()) { //if rest param exist String paramName = getStringCPEntryValue(dataInStream); - BVarSymbol restParam = new BVarSymbol(0, names.fromString(paramName), this.env.pkgSymbol.pkgID, + BVarSymbol restParam = new BVarSymbol(0, Names.fromString(paramName), this.env.pkgSymbol.pkgID, invokableType.restType, invokableSymbol, symTable.builtinPos, COMPILED_SOURCE); invokableSymbol.restParam = restParam; @@ -1072,7 +1071,7 @@ private String getStringCPEntryValue(DataInputStream dataInStream) throws IOExce return stringCPEntry.value; } - private String getStringCPEntryValue(int cpIndex) throws IOException { + private String getStringCPEntryValue(int cpIndex) { StringCPEntry stringCPEntry = (StringCPEntry) this.env.constantPool[cpIndex]; return stringCPEntry.value; } @@ -1100,10 +1099,10 @@ private PackageID createPackageID(String orgName, String pkgName, String moduleN throw new BLangCompilerException("invalid module name '" + moduleName + "' in compiled package file"); } - return new PackageID(names.fromString(orgName), - names.fromString(pkgName), - names.fromString(moduleName), - names.fromString(pkgVersion), null); + return new PackageID(Names.fromString(orgName), + Names.fromString(pkgName), + Names.fromString(moduleName), + Names.fromString(pkgVersion), null); } /** @@ -1134,7 +1133,7 @@ private static class UnresolvedType { } private class BIRTypeReader { - private DataInputStream inputStream; + private final DataInputStream inputStream; public BIRTypeReader(DataInputStream inputStream) { this.inputStream = inputStream; @@ -1155,11 +1154,11 @@ private BInvokableType setTSymbolForInvokableType(BInvokableType bInvokableType, int params = inputStream.readInt(); for (int i = 0; i < params; i++) { String paramName = getStringCPEntryValue(inputStream); - var paramFlags = inputStream.readLong(); + long paramFlags = inputStream.readLong(); byte[] docBytes = readDocBytes(inputStream); BType fieldType = readTypeFromCp(); - BVarSymbol varSymbol = new BVarSymbol(paramFlags, names.fromString(paramName), tSymbol.pkgID, + BVarSymbol varSymbol = new BVarSymbol(paramFlags, Names.fromString(paramName), tSymbol.pkgID, fieldType, tSymbol, symTable.builtinPos, COMPILED_SOURCE); @@ -1171,11 +1170,11 @@ private BInvokableType setTSymbolForInvokableType(BInvokableType bInvokableType, boolean hasRestParam = inputStream.readBoolean(); if (hasRestParam) { String fieldName = getStringCPEntryValue(inputStream); - var fieldFlags = inputStream.readLong(); + long fieldFlags = inputStream.readLong(); byte[] docBytes = readDocBytes(inputStream); BType fieldType = readTypeFromCp(); - BVarSymbol varSymbol = new BVarSymbol(fieldFlags, names.fromString(fieldName), tSymbol.pkgID, fieldType, + BVarSymbol varSymbol = new BVarSymbol(fieldFlags, Names.fromString(fieldName), tSymbol.pkgID, fieldType, tSymbol, symTable.builtinPos, COMPILED_SOURCE); defineMarkDownDocAttachment(varSymbol, docBytes); tSymbol.restParam = varSymbol; @@ -1194,7 +1193,7 @@ private BInvokableType setTSymbolForInvokableType(BInvokableType bInvokableType, private BInvokableSymbol getSymbolOfClosure() throws IOException { String name = getStringCPEntryValue(inputStream); - var flags = inputStream.readLong(); + long flags = inputStream.readLong(); BType type = readTypeFromCp(); int pkgCpIndex = inputStream.readInt(); PackageID pkgId = getPackageId(pkgCpIndex); @@ -1207,7 +1206,7 @@ private BInvokableSymbol getSymbolOfClosure() throws IOException { int parameters = inputStream.readInt(); for (int i = 0; i < parameters; i++) { String fieldName = getStringCPEntryValue(inputStream); - var fieldFlags = inputStream.readLong(); + long fieldFlags = inputStream.readLong(); byte[] docBytes = readDocBytes(inputStream); BType fieldType = readTypeFromCp(); BVarSymbol varSymbol = new BVarSymbol(fieldFlags, Names.fromString(fieldName), pkgId, fieldType, null, @@ -1220,8 +1219,8 @@ private BInvokableSymbol getSymbolOfClosure() throws IOException { public BType readType(int cpI) throws IOException { byte tag = inputStream.readByte(); - Name name = names.fromString(getStringCPEntryValue(inputStream)); - var flags = inputStream.readLong(); + Name name = Names.fromString(getStringCPEntryValue(inputStream)); + long flags = inputStream.readLong(); // Read the type flags to identify if type reference types are nullable. int typeFlags = inputStream.readInt(); @@ -1267,7 +1266,7 @@ public BType readType(int cpI) throws IOException { String recordName = getStringCPEntryValue(inputStream); BRecordTypeSymbol recordSymbol = Symbols.createRecordSymbol(Flags.asMask(EnumSet.of(Flag.PUBLIC)), - names.fromString(recordName), + Names.fromString(recordName), env.pkgSymbol.pkgID, null, env.pkgSymbol, symTable.builtinPos, COMPILED_SOURCE); @@ -1285,13 +1284,13 @@ public BType readType(int cpI) throws IOException { int recordFields = inputStream.readInt(); for (int i = 0; i < recordFields; i++) { String fieldName = getStringCPEntryValue(inputStream); - var fieldFlags = inputStream.readLong(); + long fieldFlags = inputStream.readLong(); byte[] docBytes = readDocBytes(inputStream); BType fieldType = readTypeFromCp(); - BVarSymbol varSymbol = new BVarSymbol(fieldFlags, names.fromString(fieldName), + BVarSymbol varSymbol = new BVarSymbol(fieldFlags, Names.fromString(fieldName), recordSymbol.pkgID, fieldType, recordSymbol.scope.owner, symTable.builtinPos, COMPILED_SOURCE); @@ -1322,7 +1321,7 @@ public BType readType(int cpI) throws IOException { } SymbolEnv pkgEnv = symTable.pkgEnvMap.get(packageCache.getSymbol(pkgId)); - return getType(recordType, pkgEnv, names.fromString(recordName)); + return getType(recordType, pkgEnv, Names.fromString(recordName)); case TypeTags.TYPEDESC: BTypedescType typedescType = new BTypedescType(null, symTable.typeDesc.tsymbol); typedescType.constraint = readTypeFromCp(); @@ -1337,7 +1336,7 @@ public BType readType(int cpI) throws IOException { String typeDefName = getStringCPEntryValue(inputStream); BTypeSymbol typeSymbol = Symbols.createTypeSymbol(SymTag.TYPE_REF, Flags.asMask(EnumSet.of(Flag.PUBLIC)), - names.fromString(typeDefName), pkg, null, pkgSymbol, + Names.fromString(typeDefName), pkg, null, pkgSymbol, symTable.builtinPos, COMPILED_SOURCE); boolean nullable = (typeFlags & TypeFlags.NILABLE) == TypeFlags.NILABLE; @@ -1449,7 +1448,7 @@ public BType readType(int cpI) throws IOException { pkgCpIndex = inputStream.readInt(); unionsPkgId = getPackageId(pkgCpIndex); String unionNameStr = getStringCPEntryValue(inputStream); - unionName = names.fromString(unionNameStr); + unionName = Names.fromString(unionNameStr); } BTypeSymbol unionTypeSymbol = Symbols.createTypeSymbol(SymTag.UNION_TYPE, Flags.asMask(EnumSet.of(Flag.PUBLIC)), unionName, unionsPkgId, @@ -1475,7 +1474,7 @@ public BType readType(int cpI) throws IOException { } unionType.setOriginalMemberTypes(originalMemberTypes); - var poppedUnionType = compositeStack.pop(); + Object poppedUnionType = compositeStack.pop(); assert poppedUnionType == unionType; boolean isEnum = inputStream.readBoolean(); @@ -1550,7 +1549,7 @@ public BType readType(int cpI) throws IOException { errorType.flags = flags; errorSymbol.type = errorType; errorSymbol.pkgID = pkgId; - errorSymbol.originalName = errorSymbol.name = names.fromString(errorName); + errorSymbol.originalName = errorSymbol.name = Names.fromString(errorName); Object poppedErrorType = compositeStack.pop(); assert poppedErrorType == errorType; if (!env.pkgSymbol.pkgID.equals(PackageID.ANNOTATIONS) @@ -1579,7 +1578,7 @@ public BType readType(int cpI) throws IOException { long fieldFlags = inputStream.readLong(); BType memberType = readTypeFromCp(); - BVarSymbol varSymbol = new BVarSymbol(fieldFlags, names.fromString(index), tuplePkg, + BVarSymbol varSymbol = new BVarSymbol(fieldFlags, Names.fromString(index), tuplePkg, memberType, tupleOwner, symTable.builtinPos, COMPILED_SOURCE); defineAnnotAttachmentSymbols(inputStream, varSymbol); @@ -1601,9 +1600,9 @@ public BType readType(int cpI) throws IOException { return bFutureType; case TypeTags.FINITE: String finiteTypeName = getStringCPEntryValue(inputStream); - var finiteTypeFlags = inputStream.readLong(); + long finiteTypeFlags = inputStream.readLong(); BTypeSymbol symbol = Symbols.createTypeSymbol(SymTag.FINITE_TYPE, finiteTypeFlags, - names.fromString(finiteTypeName), env.pkgSymbol.pkgID, + Names.fromString(finiteTypeName), env.pkgSymbol.pkgID, null, env.pkgSymbol, symTable.builtinPos, COMPILED_SOURCE); symbol.scope = new Scope(symbol); @@ -1624,11 +1623,11 @@ public BType readType(int cpI) throws IOException { BObjectTypeSymbol objectSymbol; if (Symbols.isFlagOn(objSymFlags, Flags.CLASS)) { - objectSymbol = Symbols.createClassSymbol(objSymFlags, names.fromString(objName), + objectSymbol = Symbols.createClassSymbol(objSymFlags, Names.fromString(objName), env.pkgSymbol.pkgID, null, env.pkgSymbol, symTable.builtinPos, COMPILED_SOURCE, false); } else { - objectSymbol = Symbols.createObjectSymbol(objSymFlags, names.fromString(objName), + objectSymbol = Symbols.createObjectSymbol(objSymFlags, Names.fromString(objName), env.pkgSymbol.pkgID, null, env.pkgSymbol, symTable.builtinPos, COMPILED_SOURCE); } @@ -1644,12 +1643,12 @@ public BType readType(int cpI) throws IOException { int fieldCount = inputStream.readInt(); for (int i = 0; i < fieldCount; i++) { String fieldName = getStringCPEntryValue(inputStream); - var fieldFlags = inputStream.readLong(); - var defaultable = inputStream.readBoolean(); + long fieldFlags = inputStream.readLong(); + boolean defaultable = inputStream.readBoolean(); byte[] docBytes = readDocBytes(inputStream); BType fieldType = readTypeFromCp(); - BVarSymbol objectVarSymbol = new BVarSymbol(fieldFlags, names.fromString(fieldName), + BVarSymbol objectVarSymbol = new BVarSymbol(fieldFlags, Names.fromString(fieldName), objectSymbol.pkgID, fieldType, objectSymbol.scope.owner, symTable.builtinPos, COMPILED_SOURCE); @@ -1690,7 +1689,7 @@ public BType readType(int cpI) throws IOException { } pkgEnv = symTable.pkgEnvMap.get(packageCache.getSymbol(pkgId)); - return getType(objectType, pkgEnv, names.fromString(objName)); + return getType(objectType, pkgEnv, Names.fromString(objName)); case TypeTags.BYTE_ARRAY: // TODO fix break; @@ -1792,11 +1791,11 @@ private void readAndSetEnumSymbol(BUnionType unionType, long flags) throws IOExc List members = new ArrayList<>(); for (int i = 0; i < memberCount; i++) { String memName = getStringCPEntryValue(inputStream); - BSymbol sym = symbolResolver.lookupSymbolInMainSpace(enumPkgEnv, names.fromString(memName)); + BSymbol sym = symbolResolver.lookupSymbolInMainSpace(enumPkgEnv, Names.fromString(memName)); members.add((BConstantSymbol) sym); } - unionType.tsymbol = new BEnumSymbol(members, flags, names.fromString(enumName), pkgSymbol.pkgID, unionType, + unionType.tsymbol = new BEnumSymbol(members, flags, Names.fromString(enumName), pkgSymbol.pkgID, unionType, pkgSymbol, symTable.builtinPos, COMPILED_SOURCE); } @@ -1804,7 +1803,7 @@ private void populateIntersectionTypeReferencedFunctions(DataInputStream inputSt BObjectTypeSymbol objectSymbol) throws IOException { String attachedFuncName = getStringCPEntryValue(inputStream); String attachedFuncOrigName = getStringCPEntryValue(inputStream); - var attachedFuncFlags = inputStream.readLong(); + long attachedFuncFlags = inputStream.readLong(); BInvokableType attachedFuncType = (BInvokableType) readTypeFromCp(); Name funcName = Names.fromString(Symbols.getAttachedFuncSymbolName( objectSymbol.name.value, attachedFuncName)); @@ -1887,8 +1886,8 @@ private PackageID getPackageId(int pkgCPIndex) { String pkgName = ((StringCPEntry) env.constantPool[pkgCpEntry.pkgNameCPIndex]).value; String moduleName = ((StringCPEntry) env.constantPool[pkgCpEntry.moduleNameCPIndex]).value; String version = ((StringCPEntry) env.constantPool[pkgCpEntry.versionCPIndex]).value; - return new PackageID(names.fromString(orgName), names.fromString(pkgName), - names.fromString(moduleName), names.fromString(version), null); + return new PackageID(Names.fromString(orgName), Names.fromString(pkgName), + Names.fromString(moduleName), Names.fromString(version), null); } private void defineValueSpace(DataInputStream dataInStream, BFiniteType finiteType, BIRTypeReader typeReader) diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/FileSystemProgramDirectory.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/FileSystemProgramDirectory.java index 629a625e42d2..19e98520fbb4 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/FileSystemProgramDirectory.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/FileSystemProgramDirectory.java @@ -37,14 +37,12 @@ import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; import java.util.stream.Stream; import static org.wso2.ballerinalang.util.LambdaExceptionUtils.rethrow; @@ -56,7 +54,7 @@ */ public class FileSystemProgramDirectory implements SourceDirectory { private final Path programDirPath; - private static PrintStream outStream = System.out; + private static final PrintStream OUT_STREAM = System.out; public FileSystemProgramDirectory(Path programDirPath) { this.programDirPath = programDirPath; @@ -83,7 +81,7 @@ public List getSourceFileNames() { fileNames = stream.map(ProjectDirs::getLastComp) .filter(ProjectDirs::isSourceFile) .map(Path::toString) - .collect(Collectors.toList()); + .toList(); } return fileNames; } catch (SecurityException | AccessDeniedException e) { @@ -112,9 +110,9 @@ public InputStream getLockFileContent() { public Path saveCompiledProgram(InputStream source, String fileName) { // When building a single bal file the executable (balx) should be generated in the current directory of // the user - Path targetFilePath = Paths.get(fileName); + Path targetFilePath = Path.of(fileName); try { - outStream.println(" " + fileName); + OUT_STREAM.println(" " + fileName); Files.copy(source, targetFilePath, StandardCopyOption.REPLACE_EXISTING); return targetFilePath; } catch (DirectoryNotEmptyException e) { @@ -174,15 +172,9 @@ public Converter getConverter() { } private String getTopLevelDirNameInPackage(CompilerOutputEntry.Kind kind, FileSystem fs) { - switch (kind) { - case SRC: - case BIR: - case OBJ: - return kind.getValue(); - case ROOT: - return fs.getSeparator(); - - } - return null; + return switch (kind) { + case SRC, BIR, OBJ -> kind.getValue(); + case ROOT -> fs.getSeparator(); + }; } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/FileSystemProjectDirectory.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/FileSystemProjectDirectory.java index a22d0cb9b704..2d5293d969a6 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/FileSystemProjectDirectory.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/FileSystemProjectDirectory.java @@ -42,7 +42,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; import java.util.stream.Stream; import static org.ballerinalang.repository.CompilerOutputEntry.Kind; @@ -58,7 +57,7 @@ public class FileSystemProjectDirectory extends FileSystemProgramDirectory { private final Path sourceDirPath; private List packageNames; protected boolean scanned = false; - private static PrintStream outStream = System.out; + private static final PrintStream OUT_STREAM = System.out; public FileSystemProjectDirectory(Path projectDirPath) { super(projectDirPath); @@ -94,7 +93,7 @@ public List getSourcePackageNames() { .filter(ProjectDirs::containsSourceFiles) .map(ProjectDirs::getLastComp) .map(Path::toString) - .collect(Collectors.toList()); + .toList(); } } catch (SecurityException | AccessDeniedException e) { throw new BLangCompilerException("permission denied: " + projectDirPath.toString()); @@ -133,7 +132,7 @@ public InputStream getLockFileContent() { public Path saveCompiledProgram(InputStream source, String fileName) { Path targetFilePath = ensureAndGetTargetDirPath().resolve(fileName); try { - outStream.println(" ./target/" + fileName); + OUT_STREAM.println(" ./target/" + fileName); Files.copy(source, targetFilePath, StandardCopyOption.REPLACE_EXISTING); return targetFilePath; } catch (DirectoryNotEmptyException e) { @@ -208,15 +207,9 @@ private void addCompilerOutputEntry(FileSystem fs, CompilerOutputEntry outputEnt } private String getTopLevelDirNameInPackage(Kind kind, FileSystem fs) { - switch (kind) { - case SRC: - case BIR: - case OBJ: - return kind.getValue(); - case ROOT: - return fs.getSeparator(); - - } - return null; + return switch (kind) { + case SRC, BIR, OBJ -> kind.getValue(); + case ROOT -> fs.getSeparator(); + }; } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/SourceDirectoryManager.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/SourceDirectoryManager.java index 81b9a9d7f33b..50688607dae6 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/SourceDirectoryManager.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/SourceDirectoryManager.java @@ -36,7 +36,6 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.List; import java.util.stream.Stream; @@ -118,7 +117,7 @@ public PackageID getPackageID(String sourcePackage) { //Check for built-in packages if (orgName.equals(Names.BUILTIN_ORG)) { - return new PackageID(orgName, names.fromString(sourcePackage), version); + return new PackageID(orgName, Names.fromString(sourcePackage), version); } //Check for source files @@ -129,7 +128,7 @@ public PackageID getPackageID(String sourcePackage) { //Check for packages List packageNames = this.sourceDirectory.getSourcePackageNames(); if (packageNames.contains(sourcePackage)) { - return new PackageID(orgName, names.fromString(sourcePackage), version); + return new PackageID(orgName, Names.fromString(sourcePackage), version); } return null; @@ -153,7 +152,7 @@ private SourceDirectory initializeAndGetSourceDirectory(CompilerContext context) throw new IllegalArgumentException("invalid project directory path"); } - Path sourceRoot = Paths.get(srcDirPathName); + Path sourceRoot = Path.of(srcDirPathName); if (Files.notExists(sourceRoot)) { throw new BLangCompilerException("'" + sourceRoot + "' project directory does not exist."); @@ -216,7 +215,7 @@ private SourceDirectory initializeAndGetSourceDirectory(CompilerContext context) private Name getOrgName(Manifest manifest) { return manifest.getProject().getOrgName() == null || manifest.getProject().getOrgName().isEmpty() ? - Names.ANON_ORG : names.fromString(manifest.getProject().getOrgName()); + Names.ANON_ORG : Names.fromString(manifest.getProject().getOrgName()); } /** diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGen.java index 2af9c4655574..9d74da3a22a2 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGen.java @@ -236,27 +236,26 @@ public class BIRGen extends BLangNodeVisitor { new CompilerContext.Key<>(); public static final String DEFAULT_WORKER_NAME = "function"; - public static final String CLONE_READ_ONLY = "cloneReadOnly"; private BIRGenEnv env; - private Names names; + private final Names names; private final SymbolTable symTable; - private BIROptimizer birOptimizer; + private final BIROptimizer birOptimizer; private final Types types; // Required variables to generate code for assignment statements private boolean varAssignment = false; - private Map typeDefs = new LinkedHashMap<>(); + private final Map typeDefs = new LinkedHashMap<>(); private BlockNode currentBlock; // This is a global variable cache public Map globalVarMap = new HashMap<>(); // This map is used to create dependencies for imported module global variables - private Map dummyGlobalVarMapForLocks = new HashMap<>(); + private final Map dummyGlobalVarMapForLocks = new HashMap<>(); - // This is to cache the lockstmt to BIR Lock - private Map lockStmtMap = new HashMap<>(); + // This is to cache the lock statement to BIR Lock + private final Map lockStmtMap = new HashMap<>(); - private Unifier unifier; + private final Unifier unifier; private BirScope currentScope; @@ -433,7 +432,7 @@ public void visit(BLangTypeDefinition astTypeDefinition) { BInvokableSymbol funcSymbol = func.symbol; BIRFunction birFunc = new BIRFunction(astTypeDefinition.pos, func.funcName, funcSymbol.flags, func.type, - names.fromString(DEFAULT_WORKER_NAME), 0, + Names.fromString(DEFAULT_WORKER_NAME), 0, funcSymbol.origin.toBIROrigin()); if (funcSymbol.receiverSymbol != null) { @@ -496,7 +495,7 @@ public void visit(BLangClassDefinition classDefinition) { BInvokableSymbol funcSymbol = func.symbol; BIRFunction birFunc = new BIRFunction(classDefinition.pos, func.funcName, funcSymbol.flags, func.type, - names.fromString(DEFAULT_WORKER_NAME), 0, funcSymbol.origin.toBIROrigin()); + Names.fromString(DEFAULT_WORKER_NAME), 0, funcSymbol.origin.toBIROrigin()); if (funcSymbol.receiverSymbol != null) { birFunc.receiver = getSelf(funcSymbol.receiverSymbol); @@ -582,12 +581,12 @@ public void visit(BLangFunction astFunc) { this.env.unlockVars.push(new BIRLockDetailsHolder()); Name funcName; if (isTypeAttachedFunction) { - funcName = names.fromString(astFunc.symbol.name.value); + funcName = Names.fromString(astFunc.symbol.name.value); } else { funcName = getFuncName(astFunc.symbol); } BIRFunction birFunc = new BIRFunction(astFunc.pos, funcName, - names.fromString(astFunc.symbol.getOriginalName().value), astFunc.symbol.flags, type, workerName, + Names.fromString(astFunc.symbol.getOriginalName().value), astFunc.symbol.flags, type, workerName, astFunc.sendsToThis.size(), astFunc.symbol.origin.toBIROrigin()); this.currentScope = new BirScope(0, null); if (astFunc.receiver != null) { @@ -892,12 +891,12 @@ private List getClosureMapOperands(BLangLambdaFunction lambdaExpr) { private Name getFuncName(BInvokableSymbol symbol) { if (symbol.receiverSymbol == null) { - return names.fromString(symbol.name.value); + return Names.fromString(symbol.name.value); } int offset = symbol.receiverSymbol.type.tsymbol.name.value.length() + 1; String attachedFuncName = symbol.name.value; - return names.fromString(attachedFuncName.substring(offset)); + return Names.fromString(attachedFuncName.substring(offset)); } private void addParam(BIRFunction birFunc, BLangVariable functionParam) { @@ -968,7 +967,7 @@ private PackageID getPackageIdForBoundMethod(BLangLambdaFunction lambdaExpr, Str } Set closureVarSymbols = lambdaExpr.function.closureVarSymbols; - if (closureVarSymbols.size() == 0) { + if (closureVarSymbols.isEmpty()) { return null; } @@ -1085,7 +1084,7 @@ public void visit(BLangSimpleVariableDef astVarDefStmt) { // This is required to pull the correct bir_variable declaration for variable references. this.env.symbolVarMap.put(astVarDefStmt.var.symbol, birVarDcl); - BirScope newScope = new BirScope(this.currentScope.id + 1, this.currentScope); + BirScope newScope = new BirScope(this.currentScope.id() + 1, this.currentScope); birVarDcl.insScope = newScope; this.currentScope = newScope; @@ -1109,8 +1108,8 @@ public void visit(BLangSimpleVariable varNode) { ANNOTATION_DATA : varNode.name.originalValue; BIRGlobalVariableDcl birVarDcl = new BIRGlobalVariableDcl(varNode.pos, varNode.symbol.flags, varNode.symbol.type, varNode.symbol.pkgID, - names.fromString(name), - names.fromString(originalName), VarScope.GLOBAL, + Names.fromString(name), + Names.fromString(originalName), VarScope.GLOBAL, VarKind.GLOBAL, varNode.name.value, varNode.symbol.origin.toBIROrigin()); birVarDcl.setMarkdownDocAttachment(varNode.symbol.markdownDocumentation); @@ -1243,7 +1242,7 @@ public void visit(BLangWorkerReceive workerReceive) { boolean isOnSameStrand = DEFAULT_WORKER_NAME.equals(this.env.enclFunc.workerName.value); this.env.enclBB.terminator = new BIRTerminator.WorkerReceive(workerReceive.pos, - names.fromString(workerReceive.getChannel().channelId()), lhsOp, isOnSameStrand, thenBB, + Names.fromString(workerReceive.getChannel().channelId()), lhsOp, isOnSameStrand, thenBB, this.currentScope); this.env.enclBasicBlocks.add(thenBB); @@ -1265,7 +1264,7 @@ public void visit(BLangWorkerAsyncSendExpr asyncSendExpr) { boolean isOnSameStrand = DEFAULT_WORKER_NAME.equals(this.env.enclFunc.workerName.value); this.env.enclBB.terminator = new BIRTerminator.WorkerSend( - asyncSendExpr.pos, names.fromString(asyncSendExpr.getChannel().channelId()), dataOp, isOnSameStrand, + asyncSendExpr.pos, Names.fromString(asyncSendExpr.getChannel().channelId()), dataOp, isOnSameStrand, false, lhsOp, thenBB, this.currentScope); this.env.enclBasicBlocks.add(thenBB); @@ -1288,7 +1287,7 @@ public void visit(BLangWorkerSyncSendExpr syncSend) { boolean isOnSameStrand = DEFAULT_WORKER_NAME.equals(this.env.enclFunc.workerName.value); this.env.enclBB.terminator = new BIRTerminator.WorkerSend( - syncSend.pos, names.fromString(syncSend.getChannel().channelId()), dataOp, isOnSameStrand, true, lhsOp, + syncSend.pos, Names.fromString(syncSend.getChannel().channelId()), dataOp, isOnSameStrand, true, lhsOp, thenBB, this.currentScope); this.env.enclBasicBlocks.add(thenBB); @@ -1762,7 +1761,7 @@ public void visit(BLangMapAccessExpr astMapAccessExpr) { keyRegIndex, varRefRegIndex, astMapAccessExpr.optionalFieldAccess, astMapAccessExpr.isLValue && !astMapAccessExpr.leafNode)); this.env.targetOperand = tempVarRef; - this.varAssignment = variableStore; + this.varAssignment = false; } @Override @@ -1789,7 +1788,7 @@ public void visit(BLangTableAccessExpr astTableAccessExpr) { setScopeAndEmit(new BIRNonTerminator.FieldAccess(astTableAccessExpr.pos, InstructionKind.TABLE_LOAD, tempVarRef, keyRegIndex, varRefRegIndex)); this.env.targetOperand = tempVarRef; - this.varAssignment = variableStore; + this.varAssignment = false; } @Override @@ -1936,7 +1935,8 @@ private BIRGlobalVariableDcl getVarRef(BLangPackageVarRef astPackageVarRefExpr) this.globalVarMap.put(symbol, globalVarDcl); } - if (!isInSamePackage(astPackageVarRefExpr.varSymbol, env.enclPkg.packageID)) { + if (!isInSamePackage(astPackageVarRefExpr.varSymbol, env.enclPkg.packageID) || + env.enclPkg.packageID.isTestPkg) { this.env.enclPkg.importedGlobalVarsDummyVarDcls.add(globalVarDcl); } return globalVarDcl; @@ -1959,7 +1959,7 @@ public void visit(BLangBinaryExpr astBinaryExpr) { // Create binary instruction BinaryOp binaryIns = new BinaryOp(astBinaryExpr.pos, getBinaryInstructionKind(astBinaryExpr.opKind), - astBinaryExpr.getBType(), lhsOp, rhsOp1, rhsOp2); + lhsOp, rhsOp1, rhsOp2); setScopeAndEmit(binaryIns); } @@ -2069,7 +2069,7 @@ public void visit(BLangXMLQName xmlQName) { this.env.enclFunc.localVars.add(tempVarDcl); BIROperand toVarRef = new BIROperand(tempVarDcl); - // If the QName is use outside of XML, treat it as string. + // If the QName is use outside XML, treat it as string. if (!xmlQName.isUsedInXML) { String qName = xmlQName.namespaceURI == null ? xmlQName.localname.value : ("{" + xmlQName.namespaceURI + "}" + xmlQName.localname); @@ -2355,8 +2355,7 @@ public void visit(BLangContinue continueStmt) { this.env.enclBasicBlocks.add(unlockBB); BIRTerminator.Unlock unlock = new BIRTerminator.Unlock(null, unlockBB, this.currentScope); this.env.enclBB.terminator = unlock; - BIRTerminator.Lock lock = toUnlock.getLock(numLocks - 1); - unlock.relatedLock = lock; + unlock.relatedLock = toUnlock.getLock(numLocks - 1); this.env.enclBB = unlockBB; numLocks--; } @@ -2661,74 +2660,43 @@ private void setScopeAndEmit(BIRNonTerminator instruction) { } private InstructionKind getBinaryInstructionKind(OperatorKind opKind) { - switch (opKind) { - case ADD: - return InstructionKind.ADD; - case SUB: - return InstructionKind.SUB; - case MUL: - return InstructionKind.MUL; - case DIV: - return InstructionKind.DIV; - case MOD: - return InstructionKind.MOD; - case EQUAL: - case EQUALS: - return InstructionKind.EQUAL; - case NOT_EQUAL: - return InstructionKind.NOT_EQUAL; - case GREATER_THAN: - return InstructionKind.GREATER_THAN; - case GREATER_EQUAL: - return InstructionKind.GREATER_EQUAL; - case LESS_THAN: - return InstructionKind.LESS_THAN; - case LESS_EQUAL: - return InstructionKind.LESS_EQUAL; - case AND: - return InstructionKind.AND; - case OR: - return InstructionKind.OR; - case REF_EQUAL: - return InstructionKind.REF_EQUAL; - case REF_NOT_EQUAL: - return InstructionKind.REF_NOT_EQUAL; - case CLOSED_RANGE: - return InstructionKind.CLOSED_RANGE; - case HALF_OPEN_RANGE: - return InstructionKind.HALF_OPEN_RANGE; - case ANNOT_ACCESS: - return InstructionKind.ANNOT_ACCESS; - case BITWISE_AND: - return InstructionKind.BITWISE_AND; - case BITWISE_OR: - return InstructionKind.BITWISE_OR; - case BITWISE_XOR: - return InstructionKind.BITWISE_XOR; - case BITWISE_LEFT_SHIFT: - return InstructionKind.BITWISE_LEFT_SHIFT; - case BITWISE_RIGHT_SHIFT: - return InstructionKind.BITWISE_RIGHT_SHIFT; - case BITWISE_UNSIGNED_RIGHT_SHIFT: - return InstructionKind.BITWISE_UNSIGNED_RIGHT_SHIFT; - default: - throw new IllegalStateException("unsupported binary operation: " + opKind.value()); - } + return switch (opKind) { + case ADD -> InstructionKind.ADD; + case SUB -> InstructionKind.SUB; + case MUL -> InstructionKind.MUL; + case DIV -> InstructionKind.DIV; + case MOD -> InstructionKind.MOD; + case EQUAL, EQUALS -> InstructionKind.EQUAL; + case NOT_EQUAL -> InstructionKind.NOT_EQUAL; + case GREATER_THAN -> InstructionKind.GREATER_THAN; + case GREATER_EQUAL -> InstructionKind.GREATER_EQUAL; + case LESS_THAN -> InstructionKind.LESS_THAN; + case LESS_EQUAL -> InstructionKind.LESS_EQUAL; + case AND -> InstructionKind.AND; + case OR -> InstructionKind.OR; + case REF_EQUAL -> InstructionKind.REF_EQUAL; + case REF_NOT_EQUAL -> InstructionKind.REF_NOT_EQUAL; + case CLOSED_RANGE -> InstructionKind.CLOSED_RANGE; + case HALF_OPEN_RANGE -> InstructionKind.HALF_OPEN_RANGE; + case ANNOT_ACCESS -> InstructionKind.ANNOT_ACCESS; + case BITWISE_AND -> InstructionKind.BITWISE_AND; + case BITWISE_OR -> InstructionKind.BITWISE_OR; + case BITWISE_XOR -> InstructionKind.BITWISE_XOR; + case BITWISE_LEFT_SHIFT -> InstructionKind.BITWISE_LEFT_SHIFT; + case BITWISE_RIGHT_SHIFT -> InstructionKind.BITWISE_RIGHT_SHIFT; + case BITWISE_UNSIGNED_RIGHT_SHIFT -> InstructionKind.BITWISE_UNSIGNED_RIGHT_SHIFT; + default -> throw new IllegalStateException("unsupported binary operation: " + opKind.value()); + }; } private InstructionKind getUnaryInstructionKind(OperatorKind opKind) { - switch (opKind) { - case TYPEOF: - return InstructionKind.TYPEOF; - case NOT: - return InstructionKind.NOT; - case SUB: - return InstructionKind.NEGATE; - case ADD: - return InstructionKind.MOVE; - default: - throw new IllegalStateException("unsupported unary operator: " + opKind.value()); - } + return switch (opKind) { + case TYPEOF -> InstructionKind.TYPEOF; + case NOT -> InstructionKind.NOT; + case SUB -> InstructionKind.NEGATE; + case ADD -> InstructionKind.MOVE; + default -> throw new IllegalStateException("unsupported unary operator: " + opKind.value()); + }; } private void generateListConstructorExpr(BLangListConstructorExpr listConstructorExpr) { @@ -2812,7 +2780,7 @@ private void generateArrayAccess(BLangIndexBasedAccess astArrayAccessExpr) { astArrayAccessExpr.isLValue && !astArrayAccessExpr.leafNode)); this.env.targetOperand = tempVarRef; - this.varAssignment = variableStore; + this.varAssignment = false; } private void generateMappingAccess(BLangIndexBasedAccess astIndexBasedAccessExpr, boolean except) { @@ -2862,7 +2830,7 @@ private void generateMappingAccess(BLangIndexBasedAccess astIndexBasedAccessExpr } else if (types.isAssignable(astAccessExprExprType, symTable.xmlType)) { generateXMLAccess((BLangXMLAccessExpr) astIndexBasedAccessExpr, tempVarRef, varRefRegIndex, keyRegIndex); - this.varAssignment = variableStore; + this.varAssignment = false; return; } else if (astAccessExprExprType.tag == TypeTags.OBJECT || (astAccessExprExprType.tag == TypeTags.UNION && diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGenEnv.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGenEnv.java index 2ddf4a1b69c5..9cf1bb8eafa0 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGenEnv.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGenEnv.java @@ -28,10 +28,11 @@ import org.wso2.ballerinalang.compiler.util.Name; import org.wso2.ballerinalang.compiler.util.Names; +import java.util.ArrayDeque; +import java.util.Deque; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Stack; /** * Stores the state such as the current node, enclosing package, function etc, during bir generation. @@ -59,7 +60,7 @@ class BIRGenEnv { BIRBasicBlock enclOnFailEndBB; BIRBasicBlock enclInnerOnFailEndBB; - Stack> trapBlocks = new Stack<>(); + Deque> trapBlocks = new ArrayDeque<>(); Map> varDclsByBlock = new HashMap<>(); @@ -67,7 +68,7 @@ class BIRGenEnv { // for example when we are to return from somewhere, we need to unlock all the // values in this list, but if we are to do break or continue, we need to pop // list and unlock variables in that - Stack unlockVars = new Stack<>(); + Deque unlockVars = new ArrayDeque<>(); // This is the basic block that contains the return instruction for the current function. // A function can have only one basic block that has a return instruction. @@ -86,12 +87,12 @@ int nextBBId() { Name nextLocalVarId(Names names) { currentLocalVarId++; - return names.merge(Names.BIR_LOCAL_VAR_PREFIX, names.fromString(Integer.toString(currentLocalVarId))); + return names.merge(Names.BIR_LOCAL_VAR_PREFIX, Names.fromString(Integer.toString(currentLocalVarId))); } Name nextLambdaVarId(Names names) { currentLambdaVarId++; - return names.merge(Names.BIR_LOCAL_VAR_PREFIX, names.fromString(Integer.toString(currentLambdaVarId))); + return names.merge(Names.BIR_LOCAL_VAR_PREFIX, Names.fromString(Integer.toString(currentLambdaVarId))); } void clear() { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGenUtils.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGenUtils.java index d033016cba9c..e4c4554216ba 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGenUtils.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/BIRGenUtils.java @@ -28,7 +28,7 @@ * * @since 2201.6.0 */ -public class BIRGenUtils { +public final class BIRGenUtils { private BIRGenUtils () { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/CodeGenerator.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/CodeGenerator.java index eefc5e9da8c2..e1865531acf6 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/CodeGenerator.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/CodeGenerator.java @@ -17,7 +17,6 @@ */ package org.wso2.ballerinalang.compiler.bir.codegen; -import org.wso2.ballerinalang.compiler.CompiledJarFile; import org.wso2.ballerinalang.compiler.PackageCache; import org.wso2.ballerinalang.compiler.bir.BIRGenUtils; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; @@ -84,7 +83,7 @@ private CompiledJarFile generate(BPackageSymbol packageSymbol, boolean isRemoteM HashMap originalIdentifierMap = JvmDesugarPhase.encodeModuleIdentifiers(packageSymbol.bir); // TODO Get-rid of the following assignment - CompiledJarFile compiledJarFile = jvmPackageGen.generate(packageSymbol.bir, true); + CompiledJarFile compiledJarFile = jvmPackageGen.generate(packageSymbol.bir); cleanUpBirPackage(packageSymbol); //Revert encoding identifier names JvmDesugarPhase.replaceEncodedModuleIdentifiers(packageSymbol.bir, originalIdentifierMap); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/CompiledJarFile.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/CompiledJarFile.java similarity index 57% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/CompiledJarFile.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/CompiledJarFile.java index 8656dc599e1c..42f16ae881b4 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/CompiledJarFile.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/CompiledJarFile.java @@ -15,10 +15,10 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler; +package org.wso2.ballerinalang.compiler.bir.codegen; -import java.util.Map; -import java.util.Optional; +import java.io.ByteArrayOutputStream; +import java.io.IOException; /** * A wrapper class for keeping code generated binary content and metadata of a program jar file. @@ -27,27 +27,13 @@ */ public class CompiledJarFile { - private String mainClassName; - private Map jarEntries; + public final JarEntries jarEntries; - public CompiledJarFile(Map jarEntries) { - - this.jarEntries = jarEntries; - } - - public CompiledJarFile(String mainClassName, Map jarEntries) { - - this.mainClassName = mainClassName; - this.jarEntries = jarEntries; + public CompiledJarFile(String mainClassName) { + this.jarEntries = new JarEntries(mainClassName); } - public Map getJarEntries() { - - return jarEntries; - } - - public Optional getMainClassName() { - - return Optional.ofNullable(mainClassName); + public ByteArrayOutputStream toByteArrayStream() throws IOException { + return jarEntries.getByteArrayOutputStream(); } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JarEntries.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JarEntries.java new file mode 100644 index 000000000000..9ef98a319eb9 --- /dev/null +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JarEntries.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (https://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 org.wso2.ballerinalang.compiler.bir.codegen; + +import io.ballerina.projects.ProjectException; +import org.apache.commons.compress.archivers.jar.JarArchiveEntry; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Map; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; + +/** + * This class holds .class files as entries of a program JAR file and converts them into a ByteArrayOutputStream. + * + * @since 2201.10.0 + */ +public class JarEntries { + private final ByteArrayOutputStream byteArrayOutputStream; + private final JarOutputStream entries; + + protected JarEntries(String mainClassName) { + this.byteArrayOutputStream = new ByteArrayOutputStream(); + try { + entries = new JarOutputStream(this.byteArrayOutputStream, getManifest(mainClassName)); + } catch (IOException e) { + throw new ProjectException("Failed to create the JarOutputStream to cache jar entries", e); + } + } + + private static Manifest getManifest(String mainClassName) { + Manifest manifest = new Manifest(); + Attributes mainAttributes = manifest.getMainAttributes(); + mainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0"); + mainAttributes.put(Attributes.Name.MAIN_CLASS, mainClassName); + return manifest; + } + + public void put(String key, byte[] value) { + JarEntry entry = new JarEntry(key); + try { + entries.putNextEntry(entry); + entries.write(value); + entries.closeEntry(); + } catch (IOException e) { + throw new ProjectException("Failed to put the jar entry", e); + } + } + + public void putResourceEntries(Map resources) { + try { + for (Map.Entry entry : resources.entrySet()) { + JarArchiveEntry e = new JarArchiveEntry(entry.getKey()); + entries.putNextEntry(e); + entries.write(entry.getValue()); + entries.closeEntry(); + } + } catch (IOException e) { + throw new ProjectException("Failed to put the resource entries", e); + } + } + + protected ByteArrayOutputStream getByteArrayOutputStream() throws IOException { + entries.close(); + return byteArrayOutputStream; + } +} diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmCastGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmCastGen.java index 9067c97c45bf..d9a5a619fb5d 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmCastGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmCastGen.java @@ -22,8 +22,8 @@ import org.objectweb.asm.MethodVisitor; import org.wso2.ballerinalang.compiler.bir.codegen.internal.BIRVarToJVMIndexMap; import org.wso2.ballerinalang.compiler.bir.codegen.internal.LabelGenerator; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JType; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JType; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags; import org.wso2.ballerinalang.compiler.semantics.analyzer.Types; import org.wso2.ballerinalang.compiler.semantics.model.SymbolTable; import org.wso2.ballerinalang.compiler.semantics.model.symbols.Symbols; @@ -161,37 +161,17 @@ void generatePlatformCheckCast(MethodVisitor mv, BIRVarToJVMIndexMap indexMap, B public void generateBToJCheckCast(MethodVisitor mv, BType sourceType, JType targetType) { sourceType = JvmCodeGenUtil.getImpliedType(sourceType); switch (targetType.jTag) { - case JTypeTags.JBYTE: - generateCheckCastBToJByte(mv, sourceType); - break; - case JTypeTags.JCHAR: - generateCheckCastBToJChar(mv, sourceType); - break; - case JTypeTags.JSHORT: - generateCheckCastBToJShort(mv, sourceType); - break; - case JTypeTags.JINT: - generateCheckCastBToJInt(mv, sourceType); - break; - case JTypeTags.JLONG: - generateCheckCastBToJLong(mv, sourceType); - break; - case JTypeTags.JFLOAT: - generateCheckCastBToJFloat(mv, sourceType); - break; - case JTypeTags.JDOUBLE: - generateCheckCastBToJDouble(mv, sourceType); - break; - case JTypeTags.JBOOLEAN: - generateCheckCastBToJBoolean(mv, sourceType); - break; - case JTypeTags.JREF: - case JTypeTags.JARRAY: - generateCheckCastBToJRef(mv, sourceType, targetType); - break; - default: - throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to" + - " 'java " + targetType + "'"); + case JTypeTags.JBYTE -> generateCheckCastBToJByte(mv, sourceType); + case JTypeTags.JCHAR -> generateCheckCastBToJChar(mv, sourceType); + case JTypeTags.JSHORT -> generateCheckCastBToJShort(mv, sourceType); + case JTypeTags.JINT -> generateCheckCastBToJInt(mv, sourceType); + case JTypeTags.JLONG -> generateCheckCastBToJLong(mv, sourceType); + case JTypeTags.JFLOAT -> generateCheckCastBToJFloat(mv, sourceType); + case JTypeTags.JDOUBLE -> generateCheckCastBToJDouble(mv, sourceType); + case JTypeTags.JBOOLEAN -> generateCheckCastBToJBoolean(mv, sourceType); + case JTypeTags.JREF, JTypeTags.JARRAY -> generateCheckCastBToJRef(mv, sourceType, targetType); + default -> throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to" + + " 'java " + targetType + "'"); } } @@ -235,26 +215,21 @@ private void generateCheckCastBToJChar(MethodVisitor mv, BType sourceType) { } switch (sourceType.tag) { - case TypeTags.BYTE: - mv.visitInsn(I2C); - break; - case TypeTags.FLOAT: + case TypeTags.BYTE -> mv.visitInsn(I2C); + case TypeTags.FLOAT -> { mv.visitInsn(D2I); mv.visitInsn(I2C); - break; - case TypeTags.HANDLE: - mv.visitMethodInsn(INVOKEVIRTUAL, HANDLE_VALUE, GET_VALUE_METHOD, - RETURN_OBJECT, false); - break; - case TypeTags.FINITE: + } + case TypeTags.HANDLE -> mv.visitMethodInsn(INVOKEVIRTUAL, HANDLE_VALUE, GET_VALUE_METHOD, + RETURN_OBJECT, false); + case TypeTags.FINITE -> { mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, ANY_TO_INT_METHOD, ANY_TO_JLONG, false); mv.visitInsn(L2I); mv.visitInsn(I2C); - break; - default: - throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to" + - " 'java char'"); + } + default -> throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to" + + " 'java char'"); } } @@ -267,25 +242,22 @@ private void generateCheckCastBToJShort(MethodVisitor mv, BType sourceType) { } switch (sourceType.tag) { - case TypeTags.BYTE: - mv.visitInsn(I2S); - break; - case TypeTags.FLOAT: + case TypeTags.BYTE -> mv.visitInsn(I2S); + case TypeTags.FLOAT -> { mv.visitInsn(D2I); mv.visitInsn(I2S); - break; - case TypeTags.HANDLE: - mv.visitMethodInsn(INVOKEVIRTUAL, HANDLE_VALUE, GET_VALUE_METHOD, - RETURN_OBJECT, false); - break; - case TypeTags.FINITE: + } + case TypeTags.HANDLE -> mv.visitMethodInsn(INVOKEVIRTUAL, HANDLE_VALUE, GET_VALUE_METHOD, + RETURN_OBJECT, false); + case TypeTags.FINITE -> { mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, ANY_TO_INT_METHOD, ANY_TO_JLONG, false); mv.visitInsn(L2I); mv.visitInsn(I2S); - break; - default: - throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to 'java short'"); + } + default -> + throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to 'java " + + "short'"); } } @@ -323,24 +295,19 @@ private void generateCheckCastBToJLong(MethodVisitor mv, BType sourceType) { } switch (sourceType.tag) { - case TypeTags.BYTE: - mv.visitInsn(I2L); - break; - case TypeTags.FLOAT: - mv.visitInsn(D2L); - break; - case TypeTags.HANDLE: + case TypeTags.BYTE -> mv.visitInsn(I2L); + case TypeTags.FLOAT -> mv.visitInsn(D2L); + case TypeTags.HANDLE -> { mv.visitMethodInsn(INVOKEVIRTUAL, HANDLE_VALUE, GET_VALUE_METHOD, RETURN_OBJECT, false); mv.visitTypeInsn(CHECKCAST, LONG_VALUE); mv.visitMethodInsn(INVOKEVIRTUAL, LONG_VALUE, "longValue", "()J", false); - break; - case TypeTags.FINITE: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, ANY_TO_INT_METHOD, ANY_TO_JLONG, - false); - break; - default: - throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to 'java long'"); + } + case TypeTags.FINITE -> mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, ANY_TO_INT_METHOD, ANY_TO_JLONG, + false); + default -> + throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to 'java " + + "long'"); } } @@ -352,23 +319,18 @@ private void generateCheckCastBToJFloat(MethodVisitor mv, BType sourceType) { } switch (sourceType.tag) { - case TypeTags.BYTE: - mv.visitInsn(I2F); - break; - case TypeTags.FLOAT: - mv.visitInsn(D2F); - break; - case TypeTags.HANDLE: - mv.visitMethodInsn(INVOKEVIRTUAL, HANDLE_VALUE, GET_VALUE_METHOD, - RETURN_OBJECT, false); - break; - case TypeTags.FINITE: + case TypeTags.BYTE -> mv.visitInsn(I2F); + case TypeTags.FLOAT -> mv.visitInsn(D2F); + case TypeTags.HANDLE -> mv.visitMethodInsn(INVOKEVIRTUAL, HANDLE_VALUE, GET_VALUE_METHOD, + RETURN_OBJECT, false); + case TypeTags.FINITE -> { mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, ANY_TO_FLOAT_METHOD, ANY_TO_JDOUBLE, false); mv.visitInsn(D2F); - break; - default: - throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to 'java float'"); + } + default -> + throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to 'java " + + "float'"); } } @@ -469,29 +431,16 @@ private void generateJToBCheckCast(MethodVisitor mv, BIRVarToJVMIndexMap indexMa break; default: switch (targetType.tag) { - case TypeTags.UNION: - generateCheckCastJToBUnionType(mv, indexMap, sourceType, (BUnionType) targetType); - break; - case TypeTags.ANYDATA: - generateCheckCastJToBAnyData(mv, indexMap, sourceType); - break; - case TypeTags.HANDLE: - generateJCastToBHandle(mv); - break; - case TypeTags.ANY: - generateJCastToBAny(mv, indexMap, sourceType, targetType); - break; - case TypeTags.JSON: - generateCheckCastJToBJSON(mv, indexMap, sourceType); - break; - case TypeTags.READONLY: - generateCheckCastJToBReadOnly(mv, indexMap, sourceType); - break; - case TypeTags.FINITE: - generateCheckCastJToBFiniteType(mv, indexMap, sourceType, targetType); - break; - default: - break; + case TypeTags.UNION -> + generateCheckCastJToBUnionType(mv, indexMap, sourceType, (BUnionType) targetType); + case TypeTags.ANYDATA -> generateCheckCastJToBAnyData(mv, indexMap, sourceType); + case TypeTags.HANDLE -> generateJCastToBHandle(mv); + case TypeTags.ANY -> generateJCastToBAny(mv, indexMap, sourceType, targetType); + case TypeTags.JSON -> generateCheckCastJToBJSON(mv, indexMap, sourceType); + case TypeTags.READONLY -> generateCheckCastJToBReadOnly(mv, indexMap, sourceType); + case TypeTags.FINITE -> generateCheckCastJToBFiniteType(mv, indexMap, sourceType, targetType); + default -> { + } } checkCast(mv, targetType); @@ -558,46 +507,30 @@ private void generateCheckCastJToBFloat(MethodVisitor mv, JType sourceType) { private void generateCheckCastJToBDecimal(MethodVisitor mv, JType sourceType) { switch (sourceType.jTag) { - case JTypeTags.JBYTE: - mv.visitMethodInsn(INVOKESTATIC, DECIMAL_VALUE, DECIMAL_VALUE_OF_J_METHOD, - DECIMAL_VALUE_OF_BOOLEAN, false); - break; - case JTypeTags.JCHAR: - mv.visitMethodInsn(INVOKESTATIC, DECIMAL_VALUE, DECIMAL_VALUE_OF_J_METHOD, - DECIMAL_VALUE_OF_CHAR, - false); - break; - case JTypeTags.JSHORT: - mv.visitMethodInsn(INVOKESTATIC, DECIMAL_VALUE, DECIMAL_VALUE_OF_J_METHOD, - DECIMAL_VALUE_OF_SHORT, - false); - break; - case JTypeTags.JINT: - mv.visitMethodInsn(INVOKESTATIC, DECIMAL_VALUE, DECIMAL_VALUE_OF_J_METHOD, - DECIMAL_VALUE_OF_INT, - false); - break; - case JTypeTags.JLONG: - mv.visitMethodInsn(INVOKESTATIC, DECIMAL_VALUE, DECIMAL_VALUE_OF_J_METHOD, - DECIMAL_VALUE_OF_LONG, - false); - break; - case JTypeTags.JFLOAT: - mv.visitMethodInsn(INVOKESTATIC, DECIMAL_VALUE, DECIMAL_VALUE_OF_J_METHOD, - DECIMAL_VALUE_OF_FLOAT, - false); - break; - case JTypeTags.JDOUBLE: - mv.visitMethodInsn(INVOKESTATIC, DECIMAL_VALUE, DECIMAL_VALUE_OF_J_METHOD, - DECIMAL_VALUE_OF_DOUBLE, - false); - break; - case JTypeTags.JREF: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, ANY_TO_DECIMAL_METHOD, ANY_TO_DECIMAL, - false); - break; - default: - throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to 'decimal'"); + case JTypeTags.JBYTE -> mv.visitMethodInsn(INVOKESTATIC, DECIMAL_VALUE, DECIMAL_VALUE_OF_J_METHOD, + DECIMAL_VALUE_OF_BOOLEAN, false); + case JTypeTags.JCHAR -> mv.visitMethodInsn(INVOKESTATIC, DECIMAL_VALUE, DECIMAL_VALUE_OF_J_METHOD, + DECIMAL_VALUE_OF_CHAR, + false); + case JTypeTags.JSHORT -> mv.visitMethodInsn(INVOKESTATIC, DECIMAL_VALUE, DECIMAL_VALUE_OF_J_METHOD, + DECIMAL_VALUE_OF_SHORT, + false); + case JTypeTags.JINT -> mv.visitMethodInsn(INVOKESTATIC, DECIMAL_VALUE, DECIMAL_VALUE_OF_J_METHOD, + DECIMAL_VALUE_OF_INT, + false); + case JTypeTags.JLONG -> mv.visitMethodInsn(INVOKESTATIC, DECIMAL_VALUE, DECIMAL_VALUE_OF_J_METHOD, + DECIMAL_VALUE_OF_LONG, + false); + case JTypeTags.JFLOAT -> mv.visitMethodInsn(INVOKESTATIC, DECIMAL_VALUE, DECIMAL_VALUE_OF_J_METHOD, + DECIMAL_VALUE_OF_FLOAT, + false); + case JTypeTags.JDOUBLE -> mv.visitMethodInsn(INVOKESTATIC, DECIMAL_VALUE, DECIMAL_VALUE_OF_J_METHOD, + DECIMAL_VALUE_OF_DOUBLE, + false); + case JTypeTags.JREF -> mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, ANY_TO_DECIMAL_METHOD, ANY_TO_DECIMAL, + false); + default -> + throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to 'decimal'"); } } @@ -662,33 +595,26 @@ private void generateJCastToBHandle(MethodVisitor mv) { private void generateJCastToBAny(MethodVisitor mv, BIRVarToJVMIndexMap indexMap, JType sourceType, BType targetType) { switch (sourceType.jTag) { - case JTypeTags.JBOOLEAN: - mv.visitMethodInsn(INVOKESTATIC, BOOLEAN_VALUE, VALUE_OF_METHOD, BOOLEAN_VALUE_OF_METHOD, false); - break; - case JTypeTags.JBYTE: - mv.visitMethodInsn(INVOKESTATIC, INT_VALUE, VALUE_OF_METHOD, INT_VALUE_OF_METHOD, false); - break; - case JTypeTags.JCHAR: - case JTypeTags.JSHORT: - case JTypeTags.JINT: + case JTypeTags.JBOOLEAN -> + mv.visitMethodInsn(INVOKESTATIC, BOOLEAN_VALUE, VALUE_OF_METHOD, BOOLEAN_VALUE_OF_METHOD, false); + case JTypeTags.JBYTE -> + mv.visitMethodInsn(INVOKESTATIC, INT_VALUE, VALUE_OF_METHOD, INT_VALUE_OF_METHOD, false); + case JTypeTags.JCHAR, JTypeTags.JSHORT, JTypeTags.JINT -> { mv.visitInsn(I2L); mv.visitMethodInsn(INVOKESTATIC, LONG_VALUE, VALUE_OF_METHOD, LONG_VALUE_OF, false); - break; - case JTypeTags.JLONG: - mv.visitMethodInsn(INVOKESTATIC, LONG_VALUE, VALUE_OF_METHOD, LONG_VALUE_OF, - false); - break; - case JTypeTags.JFLOAT: + } + case JTypeTags.JLONG -> mv.visitMethodInsn(INVOKESTATIC, LONG_VALUE, VALUE_OF_METHOD, LONG_VALUE_OF, + false); + case JTypeTags.JFLOAT -> { mv.visitInsn(F2D); mv.visitMethodInsn(INVOKESTATIC, DOUBLE_VALUE, VALUE_OF_METHOD, DOUBLE_VALUE_OF_METHOD, false); - break; - case JTypeTags.JDOUBLE: - mv.visitMethodInsn(INVOKESTATIC, DOUBLE_VALUE, VALUE_OF_METHOD, DOUBLE_VALUE_OF_METHOD, - false); - break; - case JTypeTags.JREF: + } + case JTypeTags.JDOUBLE -> + mv.visitMethodInsn(INVOKESTATIC, DOUBLE_VALUE, VALUE_OF_METHOD, DOUBLE_VALUE_OF_METHOD, + false); + case JTypeTags.JREF -> { Label afterHandle = new Label(); if (((JType.JRefType) sourceType).typeValue.equals(OBJECT)) { mv.visitInsn(DUP); @@ -707,16 +633,13 @@ private void generateJCastToBAny(MethodVisitor mv, BIRVarToJVMIndexMap indexMap, mv.visitTypeInsn(INSTANCEOF, SIMPLE_VALUE); mv.visitJumpInsn(IFNE, afterHandle); } - if (isNillable(targetType)) { mv.visitInsn(DUP); mv.visitJumpInsn(IFNULL, afterHandle); } - mv.visitInsn(DUP); mv.visitTypeInsn(INSTANCEOF, BREF_VALUE); mv.visitJumpInsn(IFNE, afterHandle); - int returnJObjectVarRefIndex = indexMap.addIfNotExists("$_ret_jobject_val_$", symbolTable.anyType); mv.visitVarInsn(ASTORE, returnJObjectVarRefIndex); mv.visitTypeInsn(NEW, HANDLE_VALUE); @@ -724,34 +647,20 @@ private void generateJCastToBAny(MethodVisitor mv, BIRVarToJVMIndexMap indexMap, mv.visitVarInsn(ALOAD, returnJObjectVarRefIndex); mv.visitMethodInsn(INVOKESPECIAL, HANDLE_VALUE, JVM_INIT_METHOD, "(Ljava/lang/Object;)V", false); mv.visitLabel(afterHandle); - break; - case JTypeTags.JARRAY: - mv.visitMethodInsn(INVOKESTATIC, HANDLE_VALUE, DECIMAL_VALUE_OF_J_METHOD, - DECIMAL_TO_HANDLE, false); - break; - default: - throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to 'any'"); + } + case JTypeTags.JARRAY -> mv.visitMethodInsn(INVOKESTATIC, HANDLE_VALUE, DECIMAL_VALUE_OF_J_METHOD, + DECIMAL_TO_HANDLE, false); + default -> throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to 'any'"); } } private static boolean isNillable(BType targetType) { - switch (targetType.tag) { - case TypeTags.NIL: - case TypeTags.NEVER: - case TypeTags.JSON: - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.READONLY: - return true; - case TypeTags.UNION: - case TypeTags.INTERSECTION: - case TypeTags.FINITE: - return targetType.isNullable(); - case TypeTags.TYPEREFDESC: - return isNillable(JvmCodeGenUtil.getImpliedType(targetType)); - default: - return false; - } + return switch (targetType.tag) { + case TypeTags.NIL, TypeTags.NEVER, TypeTags.JSON, TypeTags.ANY, TypeTags.ANYDATA, TypeTags.READONLY -> true; + case TypeTags.UNION, TypeTags.INTERSECTION, TypeTags.FINITE -> targetType.isNullable(); + case TypeTags.TYPEREFDESC -> isNillable(JvmCodeGenUtil.getImpliedType(targetType)); + default -> false; + }; } private void generateCheckCastJToBJSON(MethodVisitor mv, BIRVarToJVMIndexMap indexMap, JType sourceType) { @@ -794,71 +703,89 @@ void generateCheckCast(MethodVisitor mv, BType source, BType target, BIRVarToJVM // do nothing } else { switch (targetType.tag) { - case TypeTags.INT: + case TypeTags.INT -> { generateCheckCastToInt(mv, sourceType); return; - case TypeTags.SIGNED32_INT: + } + case TypeTags.SIGNED32_INT -> { generateCheckCastToSigned32(mv, sourceType); return; - case TypeTags.SIGNED16_INT: + } + case TypeTags.SIGNED16_INT -> { generateCheckCastToSigned16(mv, sourceType); return; - case TypeTags.SIGNED8_INT: + } + case TypeTags.SIGNED8_INT -> { generateCheckCastToSigned8(mv, sourceType); return; - case TypeTags.UNSIGNED32_INT: + } + case TypeTags.UNSIGNED32_INT -> { generateCheckCastToUnsigned32(mv, sourceType); return; - case TypeTags.UNSIGNED16_INT: + } + case TypeTags.UNSIGNED16_INT -> { generateCheckCastToUnsigned16(mv, sourceType); return; - case TypeTags.UNSIGNED8_INT: + } + case TypeTags.UNSIGNED8_INT -> { generateCheckCastToUnsigned8(mv, sourceType); return; - case TypeTags.FLOAT: + } + case TypeTags.FLOAT -> { generateCheckCastToFloat(mv, sourceType); return; - case TypeTags.STRING: + } + case TypeTags.STRING -> { generateCheckCastToString(mv, sourceType, indexMap); return; - case TypeTags.CHAR_STRING: + } + case TypeTags.CHAR_STRING -> { generateCheckCastToChar(mv, sourceType); return; - case TypeTags.DECIMAL: + } + case TypeTags.DECIMAL -> { generateCheckCastToDecimal(mv, sourceType); return; - case TypeTags.BOOLEAN: + } + case TypeTags.BOOLEAN -> { generateCheckCastToBoolean(mv, sourceType); return; - case TypeTags.BYTE: + } + case TypeTags.BYTE -> { generateCheckCastToByte(mv, sourceType); return; - case TypeTags.NIL: - case TypeTags.NEVER: + } + case TypeTags.NIL, TypeTags.NEVER -> { checkCast(mv, targetType); return; - case TypeTags.UNION: + } + case TypeTags.UNION -> { generateCheckCastToUnionType(mv, sourceType, (BUnionType) targetType); return; - case TypeTags.ANYDATA: + } + case TypeTags.ANYDATA -> { generateCheckCastToAnyData(mv, sourceType); return; - case TypeTags.ANY: + } + case TypeTags.ANY -> { generateCastToAny(mv, sourceType); return; - case TypeTags.JSON: + } + case TypeTags.JSON -> { generateCheckCastToJSON(mv, sourceType); return; - case TypeTags.READONLY: + } + case TypeTags.READONLY -> { generateCheckCastToReadonlyType(mv, sourceType, targetType); return; - case TypeTags.FINITE: + } + case TypeTags.FINITE -> { generateCheckCastToFiniteType(mv, sourceType, (BFiniteType) targetType); return; - default: + } + default -> // do the ballerina checkcast - checkCast(mv, targetType); - break; + checkCast(mv, targetType); } } @@ -876,26 +803,17 @@ private void generateCheckCastToInt(MethodVisitor mv, BType sourceType) { } switch (sourceType.tag) { - case TypeTags.BYTE: + case TypeTags.BYTE -> { mv.visitInsn(I2B); mv.visitMethodInsn(INVOKESTATIC, BYTE_VALUE, JVM_TO_UNSIGNED_INT_METHOD, "(B)I", false); mv.visitInsn(I2L); - break; - case TypeTags.FLOAT: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CONVERTER, "floatToInt", "(D)J", false); - break; - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.DECIMAL: - case TypeTags.JSON: - case TypeTags.READONLY: - case TypeTags.FINITE: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, ANY_TO_INT_METHOD, ANY_TO_JLONG, - false); - break; - default: - throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to 'int'"); + } + case TypeTags.FLOAT -> mv.visitMethodInsn(INVOKESTATIC, TYPE_CONVERTER, "floatToInt", "(D)J", false); + case TypeTags.ANY, TypeTags.ANYDATA, TypeTags.UNION, TypeTags.DECIMAL, TypeTags.JSON, TypeTags.READONLY, + TypeTags.FINITE -> + mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, ANY_TO_INT_METHOD, ANY_TO_JLONG, + false); + default -> throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to 'int'"); } } @@ -907,27 +825,18 @@ private void generateCheckCastToSigned32(MethodVisitor mv, BType sourceType) { } switch (sourceType.tag) { - case TypeTags.BYTE: + case TypeTags.BYTE -> { mv.visitInsn(I2B); mv.visitMethodInsn(INVOKESTATIC, BYTE_VALUE, JVM_TO_UNSIGNED_INT_METHOD, "(B)I", false); mv.visitInsn(I2L); - break; - case TypeTags.FLOAT: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CONVERTER, "floatToSigned32", "(D)J", false); - break; - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.DECIMAL: - case TypeTags.JSON: - case TypeTags.READONLY: - case TypeTags.FINITE: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToSigned32", ANY_TO_JLONG, - false); - break; - default: - throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' " + - "to 'int:Signed32'"); + } + case TypeTags.FLOAT -> mv.visitMethodInsn(INVOKESTATIC, TYPE_CONVERTER, "floatToSigned32", "(D)J", false); + case TypeTags.ANY, TypeTags.ANYDATA, TypeTags.UNION, TypeTags.DECIMAL, TypeTags.JSON, TypeTags.READONLY, + TypeTags.FINITE -> + mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToSigned32", ANY_TO_JLONG, + false); + default -> throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' " + + "to 'int:Signed32'"); } } @@ -939,27 +848,18 @@ private void generateCheckCastToSigned16(MethodVisitor mv, BType sourceType) { } switch (sourceType.tag) { - case TypeTags.BYTE: + case TypeTags.BYTE -> { mv.visitInsn(I2B); mv.visitMethodInsn(INVOKESTATIC, BYTE_VALUE, JVM_TO_UNSIGNED_INT_METHOD, "(B)I", false); mv.visitInsn(I2L); - break; - case TypeTags.FLOAT: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CONVERTER, "floatToSigned16", "(D)J", false); - break; - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.DECIMAL: - case TypeTags.JSON: - case TypeTags.READONLY: - case TypeTags.FINITE: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToSigned16", ANY_TO_JLONG, - false); - break; - default: - throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' " + - "to 'int:Signed16'"); + } + case TypeTags.FLOAT -> mv.visitMethodInsn(INVOKESTATIC, TYPE_CONVERTER, "floatToSigned16", "(D)J", false); + case TypeTags.ANY, TypeTags.ANYDATA, TypeTags.UNION, TypeTags.DECIMAL, TypeTags.JSON, TypeTags.READONLY, + TypeTags.FINITE -> + mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToSigned16", ANY_TO_JLONG, + false); + default -> throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' " + + "to 'int:Signed16'"); } } @@ -971,28 +871,19 @@ private void generateCheckCastToSigned8(MethodVisitor mv, BType sourceType) { } switch (sourceType.tag) { - case TypeTags.BYTE: + case TypeTags.BYTE -> { mv.visitInsn(I2B); mv.visitMethodInsn(INVOKESTATIC, BYTE_VALUE, JVM_TO_UNSIGNED_INT_METHOD, "(B)I", false); mv.visitInsn(I2L); mv.visitMethodInsn(INVOKESTATIC, TYPE_CONVERTER, "intToSigned8", "(J)J", false); - break; - case TypeTags.FLOAT: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CONVERTER, "floatToSigned8", "(D)J", false); - break; - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.DECIMAL: - case TypeTags.JSON: - case TypeTags.READONLY: - case TypeTags.FINITE: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToSigned8", ANY_TO_JLONG, - false); - break; - default: - throw new BLangCompilerException("Casting is not supported from '" + sourceType + "'" + - " to 'int:Signed8'"); + } + case TypeTags.FLOAT -> mv.visitMethodInsn(INVOKESTATIC, TYPE_CONVERTER, "floatToSigned8", "(D)J", false); + case TypeTags.ANY, TypeTags.ANYDATA, TypeTags.UNION, TypeTags.DECIMAL, TypeTags.JSON, TypeTags.READONLY, + TypeTags.FINITE -> + mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToSigned8", ANY_TO_JLONG, + false); + default -> throw new BLangCompilerException("Casting is not supported from '" + sourceType + "'" + + " to 'int:Signed8'"); } } @@ -1004,27 +895,18 @@ private void generateCheckCastToUnsigned32(MethodVisitor mv, BType sourceType) { } switch (sourceType.tag) { - case TypeTags.BYTE: + case TypeTags.BYTE -> { mv.visitInsn(I2B); mv.visitMethodInsn(INVOKESTATIC, BYTE_VALUE, JVM_TO_UNSIGNED_INT_METHOD, "(B)I", false); mv.visitInsn(I2L); - break; - case TypeTags.FLOAT: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CONVERTER, "floatToUnsigned32", "(D)J", false); - break; - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.DECIMAL: - case TypeTags.JSON: - case TypeTags.READONLY: - case TypeTags.FINITE: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToUnsigned32", ANY_TO_JLONG, - false); - break; - default: - throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to " + - "'int:Unsigned32'"); + } + case TypeTags.FLOAT -> mv.visitMethodInsn(INVOKESTATIC, TYPE_CONVERTER, "floatToUnsigned32", "(D)J", false); + case TypeTags.ANY, TypeTags.ANYDATA, TypeTags.UNION, TypeTags.DECIMAL, TypeTags.JSON, TypeTags.READONLY, + TypeTags.FINITE -> + mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToUnsigned32", ANY_TO_JLONG, + false); + default -> throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to " + + "'int:Unsigned32'"); } } @@ -1036,27 +918,17 @@ private void generateCheckCastToUnsigned16(MethodVisitor mv, BType sourceType) { } switch (sourceType.tag) { - case TypeTags.BYTE: + case TypeTags.BYTE -> { mv.visitInsn(I2B); mv.visitMethodInsn(INVOKESTATIC, BYTE_VALUE, JVM_TO_UNSIGNED_INT_METHOD, "(B)I", false); mv.visitInsn(I2L); - break; - case TypeTags.FLOAT: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CONVERTER, "floatToUnsigned16", "(D)J", false); - break; - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.DECIMAL: - case TypeTags.JSON: - case TypeTags.READONLY: - case TypeTags.FINITE: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToUnsigned16", ANY_TO_JLONG, - false); - break; - default: - throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' " + - "to 'int:Unsigned16'"); + } + case TypeTags.FLOAT -> mv.visitMethodInsn(INVOKESTATIC, TYPE_CONVERTER, "floatToUnsigned16", "(D)J", false); + case TypeTags.ANY, TypeTags.ANYDATA, TypeTags.UNION, TypeTags.DECIMAL, + TypeTags.JSON, TypeTags.READONLY, TypeTags.FINITE -> + mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToUnsigned16", ANY_TO_JLONG, false); + default -> throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' " + + "to 'int:Unsigned16'"); } } @@ -1068,27 +940,17 @@ private void generateCheckCastToUnsigned8(MethodVisitor mv, BType sourceType) { } switch (sourceType.tag) { - case TypeTags.BYTE: + case TypeTags.BYTE -> { mv.visitInsn(I2B); mv.visitMethodInsn(INVOKESTATIC, BYTE_VALUE, JVM_TO_UNSIGNED_INT_METHOD, "(B)I", false); mv.visitInsn(I2L); - break; - case TypeTags.FLOAT: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CONVERTER, "floatToUnsigned8", "(D)J", false); - break; - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.DECIMAL: - case TypeTags.JSON: - case TypeTags.READONLY: - case TypeTags.FINITE: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToUnsigned8", ANY_TO_JLONG, - false); - break; - default: - throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' " + - "to 'int:Unsigned8'"); + } + case TypeTags.FLOAT -> mv.visitMethodInsn(INVOKESTATIC, TYPE_CONVERTER, "floatToUnsigned8", "(D)J", false); + case TypeTags.ANY, TypeTags.ANYDATA, TypeTags.UNION, TypeTags.DECIMAL, + TypeTags.JSON, TypeTags.READONLY, TypeTags.FINITE -> + mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToUnsigned8", ANY_TO_JLONG, false); + default -> throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' " + + "to 'int:Unsigned8'"); } } @@ -1164,28 +1026,21 @@ private void generateCheckCastToString(MethodVisitor mv, BType sourceType, BIRVa LONG_TO_STRING, false); } else { switch (sourceType.tag) { - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.JSON: - case TypeTags.READONLY: - case TypeTags.FINITE: + case TypeTags.ANY, TypeTags.ANYDATA, TypeTags.UNION, TypeTags.JSON, + TypeTags.READONLY, TypeTags.FINITE -> { checkCast(mv, symbolTable.stringType); mv.visitTypeInsn(CHECKCAST, B_STRING_VALUE); return; - case TypeTags.FLOAT: - mv.visitMethodInsn(INVOKESTATIC, DOUBLE_VALUE, JVM_TO_STRING_METHOD, - DOUBLE_TO_STRING, false); - break; - case TypeTags.BOOLEAN: - mv.visitMethodInsn(INVOKESTATIC, BOOLEAN_VALUE, JVM_TO_STRING_METHOD, - BOOLEAN_TO_STRING, false); - break; - case TypeTags.DECIMAL: - mv.visitMethodInsn(INVOKESTATIC, STRING_VALUE, VALUE_OF_METHOD, VALUE_OF_JSTRING, false); - break; - default: - throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to 'string'"); + } + case TypeTags.FLOAT -> mv.visitMethodInsn(INVOKESTATIC, DOUBLE_VALUE, JVM_TO_STRING_METHOD, + DOUBLE_TO_STRING, false); + case TypeTags.BOOLEAN -> mv.visitMethodInsn(INVOKESTATIC, BOOLEAN_VALUE, JVM_TO_STRING_METHOD, + BOOLEAN_TO_STRING, false); + case TypeTags.DECIMAL -> + mv.visitMethodInsn(INVOKESTATIC, STRING_VALUE, VALUE_OF_METHOD, VALUE_OF_JSTRING, false); + default -> + throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to " + + "'string'"); } } @@ -1286,16 +1141,11 @@ public void generateCheckCastToAnyData(MethodVisitor mv, BType type) { private void generateCheckCastToJSON(MethodVisitor mv, BType type) { BType sourceType = JvmCodeGenUtil.getImpliedType(type); switch (sourceType.tag) { - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.READONLY: - case TypeTags.MAP: - checkCast(mv, symbolTable.jsonType); - break; - default: + case TypeTags.ANY, TypeTags.ANYDATA, TypeTags.UNION, TypeTags.READONLY, TypeTags.MAP -> + checkCast(mv, symbolTable.jsonType); + default -> // for value types, then add box instruction - generateCastToAny(mv, sourceType); + generateCastToAny(mv, sourceType); } } @@ -1325,40 +1175,19 @@ static String getTargetClass(BType targetType) { String targetTypeClass; switch (targetType.tag) { - case TypeTags.ARRAY: - case TypeTags.TUPLE: - targetTypeClass = ARRAY_VALUE; - break; - case TypeTags.MAP: - case TypeTags.RECORD: - targetTypeClass = MAP_VALUE_IMPL; - break; - case TypeTags.TABLE: - targetTypeClass = TABLE_VALUE; - break; - case TypeTags.STREAM: - targetTypeClass = STREAM_VALUE; - break; - case TypeTags.OBJECT: - targetTypeClass = B_OBJECT; - break; - case TypeTags.ERROR: - targetTypeClass = ERROR_VALUE; - break; - case TypeTags.TYPEDESC: - targetTypeClass = TYPEDESC_VALUE; - break; - case TypeTags.INVOKABLE: - targetTypeClass = FUNCTION_POINTER; - break; - case TypeTags.FUTURE: - targetTypeClass = FUTURE_VALUE; - break; - case TypeTags.HANDLE: - targetTypeClass = HANDLE_VALUE; - break; - default: + case TypeTags.ARRAY, TypeTags.TUPLE -> targetTypeClass = ARRAY_VALUE; + case TypeTags.MAP, TypeTags.RECORD -> targetTypeClass = MAP_VALUE_IMPL; + case TypeTags.TABLE -> targetTypeClass = TABLE_VALUE; + case TypeTags.STREAM -> targetTypeClass = STREAM_VALUE; + case TypeTags.OBJECT -> targetTypeClass = B_OBJECT; + case TypeTags.ERROR -> targetTypeClass = ERROR_VALUE; + case TypeTags.TYPEDESC -> targetTypeClass = TYPEDESC_VALUE; + case TypeTags.INVOKABLE -> targetTypeClass = FUNCTION_POINTER; + case TypeTags.FUTURE -> targetTypeClass = FUTURE_VALUE; + case TypeTags.HANDLE -> targetTypeClass = HANDLE_VALUE; + default -> { return null; + } } return targetTypeClass; @@ -1401,29 +1230,30 @@ void generateCast(MethodVisitor mv, BType sourceType, BType targetType) { return; } else { switch (targetType.tag) { - case TypeTags.FLOAT: + case TypeTags.FLOAT -> { generateCastToFloat(mv, sourceType); return; - case TypeTags.BOOLEAN: + } + case TypeTags.BOOLEAN -> { generateCastToBoolean(mv, sourceType); return; - case TypeTags.BYTE: + } + case TypeTags.BYTE -> { generateCastToByte(mv, sourceType); return; - case TypeTags.DECIMAL: + } + case TypeTags.DECIMAL -> { generateCastToDecimal(mv, sourceType); return; - case TypeTags.NIL: - case TypeTags.NEVER: + } + case TypeTags.NIL, TypeTags.NEVER -> { return; - case TypeTags.UNION: - case TypeTags.ANYDATA: - case TypeTags.ANY: - case TypeTags.JSON: - case TypeTags.READONLY: - case TypeTags.FINITE: + } + case TypeTags.UNION, TypeTags.ANYDATA, TypeTags.ANY, TypeTags.JSON, + TypeTags.READONLY, TypeTags.FINITE -> { generateCastToAny(mv, sourceType); return; + } } } // cast to the specific java class @@ -1440,22 +1270,12 @@ private void generateCastToInt(MethodVisitor mv, BType sourceType) { } switch (sourceType.tag) { - case TypeTags.BYTE: - mv.visitInsn(I2L); - break; - case TypeTags.FLOAT: - mv.visitInsn(D2L); - break; - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.JSON: - case TypeTags.READONLY: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, ANY_TO_INT_METHOD, ANY_TO_JLONG, - false); - break; - default: - throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to 'int'"); + case TypeTags.BYTE -> mv.visitInsn(I2L); + case TypeTags.FLOAT -> mv.visitInsn(D2L); + case TypeTags.ANY, TypeTags.ANYDATA, TypeTags.UNION, TypeTags.JSON, TypeTags.READONLY -> + mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, ANY_TO_INT_METHOD, ANY_TO_JLONG, + false); + default -> throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to 'int'"); } } @@ -1490,23 +1310,14 @@ private void generateCastToString(MethodVisitor mv, BType type) { } switch (sourceType.tag) { - case TypeTags.FLOAT: - mv.visitMethodInsn(INVOKESTATIC, DOUBLE_VALUE, JVM_TO_STRING_METHOD, - DOUBLE_TO_STRING, false); - break; - case TypeTags.BOOLEAN: - mv.visitMethodInsn(INVOKESTATIC, BOOLEAN_VALUE, JVM_TO_STRING_METHOD, - BOOLEAN_TO_STRING, false); - break; - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.JSON: - case TypeTags.READONLY: - mv.visitTypeInsn(CHECKCAST, B_STRING_VALUE); - break; - default: - throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to 'string'"); + case TypeTags.FLOAT -> mv.visitMethodInsn(INVOKESTATIC, DOUBLE_VALUE, JVM_TO_STRING_METHOD, + DOUBLE_TO_STRING, false); + case TypeTags.BOOLEAN -> mv.visitMethodInsn(INVOKESTATIC, BOOLEAN_VALUE, JVM_TO_STRING_METHOD, + BOOLEAN_TO_STRING, false); + case TypeTags.ANY, TypeTags.ANYDATA, TypeTags.UNION, TypeTags.JSON, TypeTags.READONLY -> + mv.visitTypeInsn(CHECKCAST, B_STRING_VALUE); + default -> + throw new BLangCompilerException("Casting is not supported from '" + sourceType + "' to 'string'"); } } @@ -1583,18 +1394,13 @@ private void generateCastToAny(MethodVisitor mv, BType type) { } switch (sourceType.tag) { - case TypeTags.BYTE: - mv.visitMethodInsn(INVOKESTATIC, INT_VALUE, VALUE_OF_METHOD, INT_VALUE_OF_METHOD, - false); - break; - case TypeTags.FLOAT: - mv.visitMethodInsn(INVOKESTATIC, DOUBLE_VALUE, VALUE_OF_METHOD, DOUBLE_VALUE_OF_METHOD, - false); - break; - case TypeTags.BOOLEAN: - mv.visitMethodInsn(INVOKESTATIC, BOOLEAN_VALUE, VALUE_OF_METHOD, - BOOLEAN_VALUE_OF_METHOD, false); - break; + case TypeTags.BYTE -> mv.visitMethodInsn(INVOKESTATIC, INT_VALUE, VALUE_OF_METHOD, INT_VALUE_OF_METHOD, + false); + case TypeTags.FLOAT -> + mv.visitMethodInsn(INVOKESTATIC, DOUBLE_VALUE, VALUE_OF_METHOD, DOUBLE_VALUE_OF_METHOD, + false); + case TypeTags.BOOLEAN -> mv.visitMethodInsn(INVOKESTATIC, BOOLEAN_VALUE, VALUE_OF_METHOD, + BOOLEAN_VALUE_OF_METHOD, false); } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmCodeGenUtil.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmCodeGenUtil.java index 7a4a564c981a..9d98ea87c7f0 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmCodeGenUtil.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmCodeGenUtil.java @@ -25,7 +25,6 @@ import org.ballerinalang.model.elements.PackageID; import org.ballerinalang.model.symbols.SymbolKind; import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Handle; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; @@ -36,8 +35,8 @@ import org.wso2.ballerinalang.compiler.bir.codegen.internal.NameHashComparator; import org.wso2.ballerinalang.compiler.bir.codegen.internal.ScheduleFunctionInfo; import org.wso2.ballerinalang.compiler.bir.codegen.interop.InteropMethodGen; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JType; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JType; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags; import org.wso2.ballerinalang.compiler.bir.codegen.split.JvmConstantsGen; import org.wso2.ballerinalang.compiler.bir.model.BIRAbstractInstruction; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; @@ -54,7 +53,6 @@ import org.wso2.ballerinalang.util.Flags; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.regex.Pattern; @@ -98,10 +96,11 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.JVM_TO_STRING_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MAKE_CONCAT_WITH_CONSTANTS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MAX_STRINGS_PER_METHOD; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_INIT_METHOD; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_START_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.OVERFLOW_LINE_NUMBER; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.START_OF_HEADING_WITH_SEMICOLON; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.STRAND_CLASS; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.STRAND_METADATA; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.STRAND_METADATA_VAR_PREFIX; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.STRING_BUILDER; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.STRING_CONCAT_FACTORY; @@ -122,7 +121,6 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_OBJECT; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_REGEXP; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_RUNTIME; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_STRAND_METADATA; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_STREAM_VALUE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_TABLE_VALUE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_TYPEDESC; @@ -131,7 +129,6 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INITIAL_METHOD_DESC; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_CHANNEL_DETAILS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_ERROR; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_STRAND_METADATA; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_WITH_STRING; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INT_TO_STRING; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.RETURN_ARRAY_VALUE; @@ -156,9 +153,10 @@ /** * The common functions used in CodeGen. */ -public class JvmCodeGenUtil { +public final class JvmCodeGenUtil { + public static final Unifier UNIFIER = new Unifier(); - private static final Pattern JVM_RESERVED_CHAR_SET = Pattern.compile("[\\.:/<>]"); + private static final Pattern JVM_RESERVED_CHAR_SET = Pattern.compile("[.:/<>]"); public static final String SCOPE_PREFIX = "_SCOPE_"; public static final NameHashComparator NAME_HASH_COMPARATOR = new NameHashComparator(); @@ -201,8 +199,24 @@ public static String cleanupPathSeparators(String name) { return name.replace(WINDOWS_PATH_SEPERATOR, JAVA_PACKAGE_SEPERATOR); } - public static String rewriteVirtualCallTypeName(String value) { - return Utils.encodeFunctionIdentifier(cleanupObjectTypeName(value)); + public static String rewriteVirtualCallTypeName(String value, BType objectType) { + objectType = getImpliedType(objectType); + String typeName = objectType.tsymbol.name.value; + Name originalName = objectType.tsymbol.originalName; + if (value.startsWith(typeName)) { + // The call name will be in the format of`objectTypeName.funcName` for attached functions of imported + // modules. Therefore, We need to remove the type name. + value = value.replace(typeName + ".", "").trim(); + } else if (originalName != null && value.startsWith(originalName.value)) { + // The call name will be in the format of`objectTypeOriginalName.funcName` for attached functions of + // object definitions. Therefore, We need to remove it. + value = value.replace(originalName + ".", "").trim(); + } + return Utils.encodeFunctionIdentifier(value); + } + + public static boolean isModuleInitializerMethod(String methodName) { + return methodName.equals(MODULE_INIT_METHOD) || methodName.equals(MODULE_START_METHOD); } private static String cleanupBalExt(String name) { @@ -221,53 +235,28 @@ public static String getFieldTypeSignature(BType bType) { } else if (TypeTags.isXMLTypeTag(bType.tag)) { return GET_XML; } else { - switch (bType.tag) { - case TypeTags.BYTE: - return "I"; - case TypeTags.FLOAT: - return "D"; - case TypeTags.DECIMAL: - return GET_BDECIMAL; - case TypeTags.BOOLEAN: - return "Z"; - case TypeTags.NIL: - case TypeTags.NEVER: - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.JSON: - case TypeTags.FINITE: - case TypeTags.READONLY: - return GET_OBJECT; - case TypeTags.MAP: - case TypeTags.RECORD: - return GET_MAP_VALUE; - case TypeTags.STREAM: - return GET_STREAM_VALUE; - case TypeTags.TABLE: - return GET_TABLE_VALUE; - case TypeTags.ARRAY: - case TypeTags.TUPLE: - return GET_ARRAY_VALUE; - case TypeTags.ERROR: - return GET_ERROR_VALUE; - case TypeTags.FUTURE: - return GET_FUTURE_VALUE; - case TypeTags.OBJECT: - return GET_BOBJECT; - case TypeTags.TYPEDESC: - return GET_TYPEDESC; - case TypeTags.INVOKABLE: - return GET_FUNCTION_POINTER; - case TypeTags.HANDLE: - return GET_HANDLE_VALUE; - case JTypeTags.JTYPE: - return InteropMethodGen.getJTypeSignature((JType) bType); - case TypeTags.REGEXP: - return GET_REGEXP; - default: - throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); - } + return switch (bType.tag) { + case TypeTags.BYTE -> "I"; + case TypeTags.FLOAT -> "D"; + case TypeTags.DECIMAL -> GET_BDECIMAL; + case TypeTags.BOOLEAN -> "Z"; + case TypeTags.NIL, TypeTags.NEVER, TypeTags.ANY, TypeTags.ANYDATA, TypeTags.UNION, TypeTags.JSON, + TypeTags.FINITE, TypeTags.READONLY -> + GET_OBJECT; + case TypeTags.MAP, TypeTags.RECORD -> GET_MAP_VALUE; + case TypeTags.STREAM -> GET_STREAM_VALUE; + case TypeTags.TABLE -> GET_TABLE_VALUE; + case TypeTags.ARRAY, TypeTags.TUPLE -> GET_ARRAY_VALUE; + case TypeTags.ERROR -> GET_ERROR_VALUE; + case TypeTags.FUTURE -> GET_FUTURE_VALUE; + case TypeTags.OBJECT -> GET_BOBJECT; + case TypeTags.TYPEDESC -> GET_TYPEDESC; + case TypeTags.INVOKABLE -> GET_FUNCTION_POINTER; + case TypeTags.HANDLE -> GET_HANDLE_VALUE; + case JTypeTags.JTYPE -> InteropMethodGen.getJTypeSignature((JType) bType); + case TypeTags.REGEXP -> GET_REGEXP; + default -> throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); + }; } } @@ -281,42 +270,11 @@ public static void generateDefaultConstructor(ClassWriter cw, String ownerClass) mv.visitEnd(); } - static void generateStrandMetadata(MethodVisitor mv, String moduleClass, - PackageID packageID, AsyncDataCollector asyncDataCollector) { - asyncDataCollector.getStrandMetadata().forEach( - (varName, metaData) -> genStrandMetadataField(mv, moduleClass, packageID, varName, metaData)); - } - - public static void genStrandMetadataField(MethodVisitor mv, String moduleClass, PackageID packageID, - String varName, ScheduleFunctionInfo metaData) { - mv.visitTypeInsn(Opcodes.NEW, STRAND_METADATA); - mv.visitInsn(Opcodes.DUP); - mv.visitLdcInsn(Utils.decodeIdentifier(packageID.orgName.value)); - mv.visitLdcInsn(Utils.decodeIdentifier(packageID.name.value)); - mv.visitLdcInsn(getMajorVersion(packageID.version.value)); - if (metaData.typeName == null) { - mv.visitInsn(Opcodes.ACONST_NULL); - } else { - mv.visitLdcInsn(metaData.typeName); - } - mv.visitLdcInsn(metaData.parentFunctionName); - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, STRAND_METADATA, - JVM_INIT_METHOD, INIT_STRAND_METADATA, false); - mv.visitFieldInsn(Opcodes.PUTSTATIC, moduleClass, varName, GET_STRAND_METADATA); - } - - static void visitStrandMetadataFields(ClassWriter cw, Map strandMetaDataMap) { - strandMetaDataMap.keySet().forEach(varName -> visitStrandMetadataField(cw, varName)); - } - - private static void visitStrandMetadataField(ClassWriter cw, String varName) { - FieldVisitor fv = cw.visitField(Opcodes.ACC_STATIC, varName, - GET_STRAND_METADATA, null, null); - fv.visitEnd(); - } - - public static String getStrandMetadataVarName(String parentFunction) { - return STRAND_METADATA_VAR_PREFIX + parentFunction + "$"; + public static String setAndGetStrandMetadataVarName(String parentFunction, AsyncDataCollector asyncDataCollector) { + String metaDataVarName = STRAND_METADATA_VAR_PREFIX + parentFunction + "$"; + asyncDataCollector.getStrandMetadata().putIfAbsent(metaDataVarName, + new ScheduleFunctionInfo(parentFunction)); + return metaDataVarName; } public static boolean isExternFunc(BIRNode.BIRFunction func) { @@ -328,20 +286,16 @@ public static String getPackageName(PackageID packageID) { } private static String getPackageNameWithSeparator(PackageID packageID, String separator) { - return getPackageNameWithSeparator(packageID, separator, false); - } - - private static String getPackageNameWithSeparator(PackageID packageID, String separator, boolean isSource) { String packageName = ""; String orgName = Utils.encodeNonFunctionIdentifier(packageID.orgName.value); String moduleName; - if (!packageID.isTestPkg || isSource) { + if (!packageID.isTestPkg) { moduleName = Utils.encodeNonFunctionIdentifier(packageID.name.value); } else { moduleName = Utils.encodeNonFunctionIdentifier(packageID.name.value) + Names.TEST_PACKAGE.value; } if (!moduleName.equals(ENCODED_DOT_CHARACTER)) { - if (!packageID.version.value.equals("")) { + if (!packageID.version.value.isEmpty()) { packageName = getMajorVersion(packageID.version.value) + separator; } packageName = moduleName + separator + packageName; @@ -372,6 +326,17 @@ static String getModuleLevelClassName(PackageID packageID, String sourceFileName return getPackageNameWithSeparator(packageID, separator) + className; } + public static String getModuleLevelClassName(PackageID packageID, String prefix, String sourceFileName, + String separator) { + String className = cleanupSourceFileName(sourceFileName); + // handle source file path start with '/'. + if (className.startsWith(JAVA_PACKAGE_SEPERATOR)) { + className = className.substring(1); + } + return getPackageNameWithSeparator(packageID, separator) + prefix + className; + } + + private static String cleanupSourceFileName(String name) { return name.replace(".", FILE_NAME_PERIOD_SEPERATOR); } @@ -408,51 +373,27 @@ public static String getArgTypeSignature(BType bType) { return GET_XML; } - switch (bType.tag) { - case TypeTags.BYTE: - return "I"; - case TypeTags.FLOAT: - return "D"; - case TypeTags.DECIMAL: - return GET_BDECIMAL; - case TypeTags.BOOLEAN: - return "Z"; - case TypeTags.NIL: - case TypeTags.NEVER: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.JSON: - case TypeTags.FINITE: - case TypeTags.ANY: - case TypeTags.READONLY: - return GET_OBJECT; - case TypeTags.ARRAY: - case TypeTags.TUPLE: - return GET_ARRAY_VALUE; - case TypeTags.ERROR: - return GET_ERROR_VALUE; - case TypeTags.MAP: - case TypeTags.RECORD: - return GET_MAP_VALUE; - case TypeTags.FUTURE: - return GET_FUTURE_VALUE; - case TypeTags.STREAM: - return GET_STREAM_VALUE; - case TypeTags.TABLE: - return GET_TABLE_VALUE; - case TypeTags.INVOKABLE: - return GET_FUNCTION_POINTER; - case TypeTags.TYPEDESC: - return GET_TYPEDESC; - case TypeTags.OBJECT: - return GET_BOBJECT; - case TypeTags.HANDLE: - return GET_HANDLE_VALUE; - case TypeTags.REGEXP: - return GET_REGEXP; - default: - throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); - } + return switch (bType.tag) { + case TypeTags.BYTE -> "I"; + case TypeTags.FLOAT -> "D"; + case TypeTags.DECIMAL -> GET_BDECIMAL; + case TypeTags.BOOLEAN -> "Z"; + case TypeTags.NIL, TypeTags.NEVER, TypeTags.ANYDATA, TypeTags.UNION, TypeTags.JSON, TypeTags.FINITE, + TypeTags.ANY, TypeTags.READONLY -> + GET_OBJECT; + case TypeTags.ARRAY, TypeTags.TUPLE -> GET_ARRAY_VALUE; + case TypeTags.ERROR -> GET_ERROR_VALUE; + case TypeTags.MAP, TypeTags.RECORD -> GET_MAP_VALUE; + case TypeTags.FUTURE -> GET_FUTURE_VALUE; + case TypeTags.STREAM -> GET_STREAM_VALUE; + case TypeTags.TABLE -> GET_TABLE_VALUE; + case TypeTags.INVOKABLE -> GET_FUNCTION_POINTER; + case TypeTags.TYPEDESC -> GET_TYPEDESC; + case TypeTags.OBJECT -> GET_BOBJECT; + case TypeTags.HANDLE -> GET_HANDLE_VALUE; + case TypeTags.REGEXP -> GET_REGEXP; + default -> throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); + }; } public static String generateReturnType(BType bType) { @@ -472,66 +413,27 @@ public static String generateReturnType(BType bType) { return RETURN_XML_VALUE; } - switch (bType.tag) { - case TypeTags.BYTE: - return ")I"; - case TypeTags.FLOAT: - return ")D"; - case TypeTags.DECIMAL: - return RETURN_DECIMAL_VALUE; - case TypeTags.BOOLEAN: - return ")Z"; - case TypeTags.ARRAY: - case TypeTags.TUPLE: - return RETURN_ARRAY_VALUE; - case TypeTags.MAP: - case TypeTags.RECORD: - return RETURN_MAP_VALUE; - case TypeTags.ERROR: - return RETURN_ERROR_VALUE; - case TypeTags.STREAM: - return RETURN_STREAM_VALUE; - case TypeTags.TABLE: - return RETURN_TABLE_VALUE; - case TypeTags.FUTURE: - return RETURN_FUTURE_VALUE; - case TypeTags.TYPEDESC: - return RETURN_TYPEDESC_VALUE; - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.INTERSECTION: - case TypeTags.JSON: - case TypeTags.FINITE: - case TypeTags.READONLY: - return RETURN_JOBJECT; - case TypeTags.OBJECT: - return RETURN_B_OBJECT; - case TypeTags.INVOKABLE: - return RETURN_FUNCTION_POINTER; - case TypeTags.HANDLE: - return RETURN_HANDLE_VALUE; - case TypeTags.REGEXP: - return RETURN_REGEX_VALUE; - default: - throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); - } - } - - static String cleanupObjectTypeName(String typeName) { - int index = typeName.lastIndexOf("."); // Internal type names can contain dots hence use the `lastIndexOf` - int typeNameLength = typeName.length(); - if (index > 1 && typeName.charAt(index - 1) == '\\') { // Methods can contain escaped characters - return typeName; - } else if (index > 0 && index != typeNameLength - 1) { // Resource method name can contain . at the end - return typeName.substring(index + 1); - } else if (index > 0) { - // We will reach here for resource methods eg: (MyClient8.$get$.) - index = typeName.substring(0, typeNameLength - 1).lastIndexOf("."); // Index of the . before the last . - return typeName.substring(index + 1); - } - - return typeName; + return switch (bType.tag) { + case TypeTags.BYTE -> ")I"; + case TypeTags.FLOAT -> ")D"; + case TypeTags.DECIMAL -> RETURN_DECIMAL_VALUE; + case TypeTags.BOOLEAN -> ")Z"; + case TypeTags.ARRAY, TypeTags.TUPLE -> RETURN_ARRAY_VALUE; + case TypeTags.MAP, TypeTags.RECORD -> RETURN_MAP_VALUE; + case TypeTags.ERROR -> RETURN_ERROR_VALUE; + case TypeTags.STREAM -> RETURN_STREAM_VALUE; + case TypeTags.TABLE -> RETURN_TABLE_VALUE; + case TypeTags.FUTURE -> RETURN_FUTURE_VALUE; + case TypeTags.TYPEDESC -> RETURN_TYPEDESC_VALUE; + case TypeTags.ANY, TypeTags.ANYDATA, TypeTags.UNION, TypeTags.INTERSECTION, TypeTags.JSON, + TypeTags.FINITE, TypeTags.READONLY -> + RETURN_JOBJECT; + case TypeTags.OBJECT -> RETURN_B_OBJECT; + case TypeTags.INVOKABLE -> RETURN_FUNCTION_POINTER; + case TypeTags.HANDLE -> RETURN_HANDLE_VALUE; + case TypeTags.REGEXP -> RETURN_REGEX_VALUE; + default -> throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); + }; } public static void loadChannelDetails(MethodVisitor mv, List channels, @@ -618,7 +520,7 @@ private static BirScope getLastScope(BIRAbstractInstruction instruction, String BirScope scope = instruction.scope; if (scope != null && scope != lastScope) { lastScope = scope; - Label scopeLabel = labelGen.getLabel(funcName + SCOPE_PREFIX + scope.id); + Label scopeLabel = labelGen.getLabel(funcName + SCOPE_PREFIX + scope.id()); mv.visitLabel(scopeLabel); storeLabelForParentScopes(scope, scopeLabel, labelGen, funcName, visitedScopesSet); visitedScopesSet.add(scope); @@ -629,9 +531,9 @@ private static BirScope getLastScope(BIRAbstractInstruction instruction, String private static void storeLabelForParentScopes(BirScope scope, Label scopeLabel, LabelGenerator labelGen, String funcName, Set visitedScopesSet) { - BirScope parent = scope.parent; + BirScope parent = scope.parent(); if (parent != null && !visitedScopesSet.contains(parent)) { - String labelName = funcName + SCOPE_PREFIX + parent.id; + String labelName = funcName + SCOPE_PREFIX + parent.id(); labelGen.putLabel(labelName, scopeLabel); visitedScopesSet.add(parent); @@ -645,7 +547,7 @@ public static BirScope getLastScopeFromTerminator(MethodVisitor mv, BIRNode.BIRB BirScope scope = bb.terminator.scope; if (scope != null && scope != lastScope) { lastScope = scope; - Label scopeLabel = labelGen.getLabel(funcName + SCOPE_PREFIX + scope.id); + Label scopeLabel = labelGen.getLabel(funcName + SCOPE_PREFIX + scope.id()); mv.visitLabel(scopeLabel); visitedScopesSet.add(scope); } @@ -664,10 +566,10 @@ public static void genYieldCheck(MethodVisitor mv, LabelGenerator labelGen, BIRN mv.visitJumpInsn(GOTO, gotoLabel); } - protected static void generateSetYieldedStatus(MethodVisitor mv, LabelGenerator labelGen, String funcName, - int yieldLocationVarIndex, Location terminatorPos, - String fullyQualifiedFuncName, String yieldStatus, - int yieldStatusVarIndex) { + static void generateSetYieldedStatus(MethodVisitor mv, LabelGenerator labelGen, String funcName, + int yieldLocationVarIndex, Location terminatorPos, + String fullyQualifiedFuncName, String yieldStatus, + int yieldStatusVarIndex) { Label yieldLocationLabel = new Label(); mv.visitJumpInsn(IFEQ, yieldLocationLabel); @@ -715,30 +617,18 @@ public static String cleanupFunctionName(String functionName) { public static boolean isSimpleBasicType(BType bType) { bType = JvmCodeGenUtil.getImpliedType(bType); - switch (bType.tag) { - case TypeTags.BYTE: - case TypeTags.FLOAT: - case TypeTags.BOOLEAN: - case TypeTags.DECIMAL: - case TypeTags.NIL: - case TypeTags.NEVER: - return true; - default: - return (TypeTags.isIntegerTypeTag(bType.tag)) || (TypeTags.isStringTypeTag(bType.tag)); - } + return switch (bType.tag) { + case TypeTags.BYTE, TypeTags.FLOAT, TypeTags.BOOLEAN, TypeTags.DECIMAL, TypeTags.NIL, TypeTags.NEVER -> + true; + default -> (TypeTags.isIntegerTypeTag(bType.tag)) || (TypeTags.isStringTypeTag(bType.tag)); + }; } public static boolean needNoTypeGeneration(int bTypeTag) { - switch (bTypeTag) { - case TypeTags.RECORD: - case TypeTags.ERROR: - case TypeTags.OBJECT: - case TypeTags.UNION: - case TypeTags.TUPLE: - return false; - default: - return true; - } + return switch (bTypeTag) { + case TypeTags.RECORD, TypeTags.ERROR, TypeTags.OBJECT, TypeTags.UNION, TypeTags.TUPLE -> false; + default -> true; + }; } /** @@ -750,7 +640,6 @@ public static boolean needNoTypeGeneration(int bTypeTag) { * else returns the original type */ public static BType getImpliedType(BType type) { - BType constraint = type; if (type == null) { return null; } @@ -763,7 +652,7 @@ public static BType getImpliedType(BType type) { return getImpliedType(((BIntersectionType) type).effectiveType); } - return constraint; + return type; } public static void loadConstantValue(BType bType, Object constVal, MethodVisitor mv, @@ -784,32 +673,28 @@ public static void loadConstantValue(BType bType, Object constVal, MethodVisitor } switch (typeTag) { - case TypeTags.BYTE: + case TypeTags.BYTE -> { int byteValue = ((Number) constVal).intValue(); mv.visitLdcInsn(byteValue); - break; - case TypeTags.FLOAT: + } + case TypeTags.FLOAT -> { double doubleValue = constVal instanceof Double ? (double) constVal : Double.parseDouble(String.valueOf(constVal)); mv.visitLdcInsn(doubleValue); - break; - case TypeTags.BOOLEAN: + } + case TypeTags.BOOLEAN -> { boolean booleanVal = constVal instanceof Boolean ? (boolean) constVal : Boolean.parseBoolean(String.valueOf(constVal)); mv.visitLdcInsn(booleanVal); - break; - case TypeTags.DECIMAL: + } + case TypeTags.DECIMAL -> { mv.visitTypeInsn(NEW, DECIMAL_VALUE); mv.visitInsn(DUP); mv.visitLdcInsn(removeDecimalDiscriminator(String.valueOf(constVal))); mv.visitMethodInsn(INVOKESPECIAL, DECIMAL_VALUE, JVM_INIT_METHOD, INIT_WITH_STRING, false); - break; - case TypeTags.NIL: - case TypeTags.NEVER: - mv.visitInsn(ACONST_NULL); - break; - default: - throw new BLangCompilerException("JVM generation is not supported for type : " + bType); + } + case TypeTags.NIL, TypeTags.NEVER -> mv.visitInsn(ACONST_NULL); + default -> throw new BLangCompilerException("JVM generation is not supported for type : " + bType); } } @@ -878,4 +763,50 @@ public static void visitMaxStackForMethod(MethodVisitor mv, String funcName, Str Utils.decodeIdentifier(className) + "'", e); } } + + public static String getMethodSig(Class returnType, Class... parameterTypes) { + + StringBuilder sb = new StringBuilder(); + sb.append('('); + for (Class type : parameterTypes) { + sb.append(getSig(type)); + } + sb.append(')'); + return sb.append(getSig(returnType)).toString(); + } + + public static String getSig(Class c) { + + if (c.isPrimitive()) { + if (int.class == c) { + return "I"; + } else if (long.class == c) { + return "J"; + } else if (boolean.class == c) { + return "Z"; + } else if (byte.class == c) { + return "B"; + } else if (short.class == c) { + return "S"; + } else if (char.class == c) { + return "C"; + } else if (float.class == c) { + return "F"; + } else if (double.class == c) { + return "D"; + } else { + // This is void + return "V"; + } + } else if (void.class == c || Void.class == c) { + return "V"; + } else { + String className = c.getName().replace('.', '/'); + if (c.isArray()) { + return className; + } else { + return 'L' + className + ';'; + } + } + } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmConstants.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmConstants.java index eb0517dd2117..f510a244f281 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmConstants.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmConstants.java @@ -29,7 +29,7 @@ * * @since 1.2.0 */ -public class JvmConstants { +public final class JvmConstants { // jvm values public API classes public static final String B_XML_QNAME = "io/ballerina/runtime/api/values/BXmlQName"; @@ -44,7 +44,6 @@ public class JvmConstants { public static final String STREAM_VALUE = "io/ballerina/runtime/internal/values/StreamValue"; public static final String TABLE_VALUE = "io/ballerina/runtime/internal/values/TableValue"; public static final String ARRAY_VALUE = "io/ballerina/runtime/internal/values/ArrayValue"; - public static final String OBJECT_VALUE = "io/ballerina/runtime/internal/values/ObjectValue"; public static final String ABSTRACT_OBJECT_VALUE = "io/ballerina/runtime/internal/values/AbstractObjectValue"; public static final String BREF_VALUE = "io/ballerina/runtime/api/values/BRefValue"; public static final String REF_VALUE = "io/ballerina/runtime/internal/values/RefValue"; @@ -73,7 +72,6 @@ public class JvmConstants { public static final String LOCK_STORE = "io/ballerina/runtime/internal/BLockStore"; public static final String FUNCTION_POINTER = "io/ballerina/runtime/internal/values/FPValue"; public static final String ARRAY_VALUE_IMPL = "io/ballerina/runtime/internal/values/ArrayValueImpl"; - public static final String TUPLE_VALUE_IMPL = "io/ballerina/runtime/internal/values/TupleValueImpl"; public static final String TABLE_VALUE_IMPL = "io/ballerina/runtime/internal/values/TableValueImpl"; public static final String SIMPLE_VALUE = "io/ballerina/runtime/internal/values/SimpleValue"; public static final String REG_EXP_VALUE = "io/ballerina/runtime/internal/values/RegExpValue"; @@ -110,7 +108,6 @@ public class JvmConstants { public static final String PREDEFINED_TYPES = "io/ballerina/runtime/api/PredefinedTypes"; public static final String ARRAY_TYPE = "io/ballerina/runtime/api/types/ArrayType"; - public static final String MAP_TYPE = "io/ballerina/runtime/api/types/MapType"; public static final String XML_TYPE = "io/ballerina/runtime/api/types/XmlType"; public static final String JSON_TYPE = "io/ballerina/runtime/api/types/JsonType"; public static final String STREAM_TYPE = "io/ballerina/runtime/api/types/StreamType"; @@ -126,9 +123,7 @@ public class JvmConstants { public static final String FIELD = "io/ballerina/runtime/api/types/Field"; public static final String METHOD_TYPE = "io/ballerina/runtime/api/types/MethodType"; public static final String RESOURCE_METHOD_TYPE = "io/ballerina/runtime/api/types/ResourceMethodType"; - public static final String REMOTE_METHOD_TYPE = "io/ballerina/runtime/api/types/RemoteMethodType"; public static final String FINITE_TYPE = "io/ballerina/runtime/api/types/FiniteType"; - public static final String FUTURE_TYPE = "io/ballerina/runtime/api/types/FutureType"; public static final String INTEGER_TYPE = "io/ballerina/runtime/api/types/IntegerType"; public static final String BYTE_TYPE = "io/ballerina/runtime/api/types/ByteType"; public static final String FLOAT_TYPE = "io/ballerina/runtime/api/types/FloatType"; @@ -182,11 +177,9 @@ public class JvmConstants { public static final String VARIABLE_KEY = "io/ballerina/runtime/internal/configurable/VariableKey"; public static final String CONFIG_DETAILS = "io/ballerina/runtime/internal/configurable/providers/ConfigDetails"; - public static final String CLI_TEST_ARGS = "io/ballerina/runtime/internal/configurable/providers/cli/CliTestArgs"; public static final String TEST_ARGUMENTS = "io/ballerina/runtime/internal/testable/TestArguments"; public static final String TEST_CONFIG_ARGS = "io/ballerina/runtime/internal/testable/TestConfigArguments"; public static final String TYPE_ID_SET = "io/ballerina/runtime/internal/types/BTypeIdSet"; - public static final String TYPE_ID = "io/ballerina/runtime/internal/types/BTypeIdSet$TypeId"; // other jvm-specific classes public static final String TYPE_CHECKER = "io/ballerina/runtime/internal/TypeChecker"; @@ -196,9 +189,7 @@ public class JvmConstants { public static final String STRAND_METADATA = "io/ballerina/runtime/api/async/StrandMetadata"; public static final String BAL_ENV_CLASS = "io/ballerina/runtime/internal/BalEnvironment"; public static final String BAL_ENV = "io/ballerina/runtime/api/Environment"; - public static final String BAL_FUTURE = "io/ballerina/runtime/api/Future"; public static final String TYPE_CONVERTER = "io/ballerina/runtime/internal/TypeConverter"; - public static final String STRAND_STATE = "io/ballerina/runtime/internal/scheduling/State"; public static final String FUNCTION_FRAME = "io/ballerina/runtime/internal/scheduling/FunctionFrame"; public static final String VALUE_CREATOR = "io/ballerina/runtime/internal/values/ValueCreator"; public static final String XML_FACTORY = "io/ballerina/runtime/internal/XmlFactory"; @@ -211,7 +202,6 @@ public class JvmConstants { public static final String TABLE_UTILS = "io/ballerina/runtime/internal/TableUtils"; public static final String STRING_UTILS = "io/ballerina/runtime/api/utils/StringUtils"; public static final String ERROR_UTILS = "io/ballerina/runtime/internal/ErrorUtils"; - public static final String ERROR_CREATOR = "io/ballerina/runtime/api/ErrorCreator"; public static final String RUNTIME_UTILS = "io/ballerina/runtime/internal/util/RuntimeUtils"; public static final String LARGE_STRUCTURE_UTILS = "io/ballerina/runtime/internal/util/LargeStructureUtils"; public static final String OPTION = "io/ballerina/runtime/internal/cli/Option"; @@ -238,7 +228,6 @@ public class JvmConstants { public static final String SET = "java/util/Set"; public static final String LINKED_HASH_SET = "java/util/LinkedHashSet"; public static final String STRING_BUILDER = "java/lang/StringBuilder"; - public static final String COMPARABLE = "java/lang/Comparable"; public static final String FUNCTION = "java/util/function/Function"; public static final String LONG_STREAM = "java/util/stream/LongStream"; public static final String JAVA_THREAD = "java/lang/Thread"; @@ -249,9 +238,7 @@ public class JvmConstants { public static final String NUMBER = "java/lang/Number"; public static final String HASH_MAP = "java/util/HashMap"; public static final String PATH = "java/nio/file/Path"; - public static final String PATHS = "java/nio/file/Paths"; public static final String SYSTEM = "java/lang/System"; - public static final String BIG_DECIMAL = "java/math/BigDecimal"; public static final String STRING_CONCAT_FACTORY = "java/lang/invoke/StringConcatFactory"; public static final String RECEIVE_FIELD = "io/ballerina/runtime/internal/scheduling/WDChannels$ReceiveField"; @@ -269,7 +256,6 @@ public class JvmConstants { // error related constants public static final String PANIC_FIELD = "panic"; - public static final String PRINT_STACK_TRACE_METHOD = "printStackTrace"; public static final String SET_DETAIL_TYPE_METHOD = "setDetailType"; public static final String SET_TYPEID_SET_METHOD = "setTypeIdSet"; public static final String TRAP_ERROR_METHOD = "trapError"; @@ -305,6 +291,7 @@ public class JvmConstants { public static final String MODULE_STRING_CONSTANT_CLASS_NAME = "constants/$_string_constants"; public static final String MODULE_SURROGATES_CLASS_NAME = "constants/$_surrogate_methods"; public static final String MODULE_CONSTANT_CLASS_NAME = "constants/$_module_constants"; + public static final String MODULE_STRAND_METADATA_CLASS_NAME = "constants/$_strand_metadata"; public static final String CONSTANTS_CLASS_NAME = "constants/$_constants"; public static final String MODULE_TYPES_CLASS_NAME = "types/$_types"; public static final String MODULE_RECORD_TYPES_CLASS_NAME = "types/$_record_types"; @@ -318,6 +305,8 @@ public class JvmConstants { public static final String MODULE_FUNCTION_CALLS_CLASS_NAME = "creators/$_function_calls"; public static final String MODULE_ERRORS_CREATOR_CLASS_NAME = "creators/$_errors"; public static final String MODULE_ANNOTATIONS_CLASS_NAME = "annotations/$_annotations"; + public static final String MODULE_GENERATED_FUNCTIONS_CLASS_NAME = "functions/$_generated"; + public static final String MODULE_LAMBDAS_CLASS_NAME = "lambdas/$_generated"; public static final String B_STRING_INIT_METHOD_PREFIX = "$string_init"; public static final String B_UNION_TYPE_INIT_METHOD = "$union_type_init"; public static final String B_ERROR_TYPE_INIT_METHOD = "$error_type_init"; @@ -333,6 +322,7 @@ public class JvmConstants { public static final String CONSTANT_INIT_METHOD_PREFIX = "$constant_init"; public static final String ANNOTATIONS_METHOD_PREFIX = "$process_annotations"; public static final String CURRENT_MODULE_INIT = "$currentModuleInit"; + public static final String CURRENT_MODULE_STOP = "$currentModuleStop"; public static final String MODULE_INIT_METHOD = "$moduleInit"; public static final String MODULE_START_METHOD = "$moduleStart"; public static final String MODULE_STOP_METHOD = "$moduleStop"; @@ -341,7 +331,6 @@ public class JvmConstants { public static final String MAIN_METHOD = "main"; public static final String BAL_EXTENSION = ".bal"; public static final String WINDOWS_PATH_SEPERATOR = "\\"; - public static final String UNIX_PATH_SEPERATOR = "/"; public static final String JAVA_PACKAGE_SEPERATOR = "/"; public static final String FILE_NAME_PERIOD_SEPERATOR = "$$$"; public static final String VALUE_CLASS_PREFIX = "$value$"; @@ -354,6 +343,8 @@ public class JvmConstants { DEFAULT_VERSION); public static final String BUILT_IN_PACKAGE_NAME = "lang" + ENCODED_DOT_CHARACTER + "annotations"; public static final String MODULE_START_ATTEMPTED = "$moduleStartAttempted"; + public static final String PARENT_MODULE_START_ATTEMPTED = "$parentModuleStartAttempted"; + public static final String NO_OF_DEPENDANT_MODULES = "$noOfDependantModules"; public static final String MODULE_STARTED = "$moduleStarted"; public static final String WRAPPER_GEN_BB_ID_NAME = "wrapperGen"; public static final String JVM_INIT_METHOD = ""; @@ -381,6 +372,7 @@ public class JvmConstants { public static final String CONFIGURE_INIT = "$configureInit"; public static final String CONFIGURATION_CLASS_NAME = "$configurationMapper"; public static final String POPULATE_CONFIG_DATA_METHOD = "$initAndPopulateConfigData"; + public static final String CONFIGURE_INIT_ATTEMPTED = "$configureInitAttempted"; public static final String HANDLE_ANYDATA_VALUES = "handleAnydataValues"; public static final String MAKE_CONCAT_WITH_CONSTANTS = "makeConcatWithConstants"; public static final String START_OF_HEADING_WITH_SEMICOLON = ":\u0001"; @@ -444,17 +436,7 @@ public class JvmConstants { public static final String GET_STRING_VALUE = "getStringValue"; public static final String GET_UNBOXED_BOOLEAN_VALUE = "getUnboxedBooleanValue"; // visibility flags - public static final int BAL_PUBLIC = 1; - public static final int BAL_NATIVE = 2; - public static final int BAL_ATTACHED = 8; - public static final int BAL_REQUIRED = 256; - public static final int BAL_PRIVATE = 1024; public static final int BAL_OPTIONAL = 4096; - public static final int BAL_SERVICE = 262144; - - // type flags - public static final int TYPE_FLAG_PURETYPE = 4; - public static final String TYPE_NOT_SUPPORTED_MESSAGE = "JVM generation is not supported for type "; @@ -475,6 +457,8 @@ public class JvmConstants { public static final int MAX_STRINGS_PER_METHOD = 5000; public static final int VISIT_MAX_SAFE_MARGIN = 10; public static final int OVERFLOW_LINE_NUMBER = 0x80000000; + public static final int MAX_GENERATED_METHODS_PER_CLASS = 100; + public static final int MAX_GENERATED_LAMBDAS_PER_CLASS = 500; private JvmConstants() { } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmDesugarPhase.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmDesugarPhase.java index b406cce3835e..7d00e3cf63ae 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmDesugarPhase.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmDesugarPhase.java @@ -56,7 +56,7 @@ * * @since 1.2.0 */ -public class JvmDesugarPhase { +public final class JvmDesugarPhase { private JvmDesugarPhase() { } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmErrorGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmErrorGen.java index c0fb9d134a49..c77ba0bd9e8f 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmErrorGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmErrorGen.java @@ -22,8 +22,8 @@ import org.objectweb.asm.MethodVisitor; import org.wso2.ballerinalang.compiler.bir.codegen.internal.BIRVarToJVMIndexMap; import org.wso2.ballerinalang.compiler.bir.codegen.internal.LabelGenerator; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.CatchIns; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JErrorEntry; +import org.wso2.ballerinalang.compiler.bir.codegen.model.CatchIns; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JErrorEntry; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; import org.wso2.ballerinalang.compiler.bir.model.BIRTerminator; @@ -94,8 +94,7 @@ public void generateTryCatch(BIRNode.BIRFunction func, String funcName, BIRNode. this.mv.visitLabel(endLabel); this.mv.visitJumpInsn(GOTO, jumpLabel); - if (currentEE instanceof JErrorEntry) { - JErrorEntry jCurrentEE = ((JErrorEntry) currentEE); + if (currentEE instanceof JErrorEntry jCurrentEE) { BIRNode.BIRVariableDcl retVarDcl = currentEE.errorOp.variableDcl; int retIndex = this.indexMap.addIfNotExists(retVarDcl.name.value, retVarDcl.type); boolean exeptionExist = false; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmInstructionGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmInstructionGen.java index ebc34359cd69..1f18e04c03ae 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmInstructionGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmInstructionGen.java @@ -27,13 +27,14 @@ import org.objectweb.asm.MethodVisitor; import org.wso2.ballerinalang.compiler.bir.codegen.internal.AsyncDataCollector; import org.wso2.ballerinalang.compiler.bir.codegen.internal.BIRVarToJVMIndexMap; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JCast; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JInstruction; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JLargeArrayInstruction; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JLargeMapInstruction; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JMethodCallInstruction; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JType; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags; +import org.wso2.ballerinalang.compiler.bir.codegen.internal.LambdaFunction; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JCast; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JInstruction; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JLargeArrayInstruction; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JLargeMapInstruction; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JMethodCallInstruction; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JType; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags; import org.wso2.ballerinalang.compiler.bir.codegen.split.JvmConstantsGen; import org.wso2.ballerinalang.compiler.bir.model.BIRInstruction; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; @@ -249,8 +250,8 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.LONG_STREAM_RANGE_CLOSED; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.OBJECT_TYPE_DUPLICATE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.OBJECT_TYPE_IMPL_INIT; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.PASS_B_STRING_RETURN_UNBOXED_BOOLEAN; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.PASS_B_STRING_RETURN_B_STRING; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.PASS_B_STRING_RETURN_UNBOXED_BOOLEAN; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.PASS_B_STRING_RETURN_UNBOXED_DOUBLE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.PASS_B_STRING_RETURN_UNBOXED_LONG; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.PASS_OBJECT_RETURN_OBJECT; @@ -283,7 +284,7 @@ public class JvmInstructionGen { public static final String TO_UNSIGNED_LONG = "toUnsignedLong"; public static final String ANON_METHOD_DELEGATE = "$anon$method$delegate$"; - //this anytype is currently set from package gen class + //this any type is currently set from package gen class static BType anyType; private final MethodVisitor mv; private final BIRVarToJVMIndexMap indexMap; @@ -295,7 +296,7 @@ public class JvmInstructionGen { private final SymbolTable symbolTable; private final AsyncDataCollector asyncDataCollector; private final JvmTypeTestGen typeTestGen; - private final Map functions; + private final Map functions; private final String moduleInitClass; public JvmInstructionGen(MethodVisitor mv, BIRVarToJVMIndexMap indexMap, PackageID currentPackage, @@ -322,127 +323,65 @@ static void addJUnboxInsn(MethodVisitor mv, JType jType) { } switch (jType.jTag) { - case JTypeTags.JBYTE: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToJByte", ANY_TO_JBYTE, false); - break; - case JTypeTags.JCHAR: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToJChar", ANY_TO_JCHAR, false); - break; - case JTypeTags.JSHORT: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToJShort", ANY_TO_JSTRING, false); - break; - case JTypeTags.JINT: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToJInt", ANY_TO_BYTE, false); - break; - case JTypeTags.JLONG: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToJLong", ANY_TO_JLONG, false); - break; - case JTypeTags.JFLOAT: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToJFloat", ANY_TO_JFLOAT, false); - break; - case JTypeTags.JDOUBLE: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToJDouble", ANY_TO_JDOUBLE, false); - break; - case JTypeTags.JBOOLEAN: - mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToJBoolean", ANY_TO_JBOOLEAN, - false); - break; - case JTypeTags.JREF: - mv.visitTypeInsn(CHECKCAST, ((JType.JRefType) jType).typeValue); - break; + case JTypeTags.JBYTE -> mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToJByte", ANY_TO_JBYTE, false); + case JTypeTags.JCHAR -> mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToJChar", ANY_TO_JCHAR, false); + case JTypeTags.JSHORT -> + mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToJShort", ANY_TO_JSTRING, false); + case JTypeTags.JINT -> mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToJInt", ANY_TO_BYTE, false); + case JTypeTags.JLONG -> mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToJLong", ANY_TO_JLONG, false); + case JTypeTags.JFLOAT -> + mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToJFloat", ANY_TO_JFLOAT, false); + case JTypeTags.JDOUBLE -> + mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToJDouble", ANY_TO_JDOUBLE, false); + case JTypeTags.JBOOLEAN -> mv.visitMethodInsn(INVOKESTATIC, TYPE_CHECKER, "anyToJBoolean", ANY_TO_JBOOLEAN, + false); + case JTypeTags.JREF -> mv.visitTypeInsn(CHECKCAST, ((JType.JRefType) jType).typeValue); } } private void generateJVarLoad(MethodVisitor mv, JType jType, int valueIndex) { switch (jType.jTag) { - case JTypeTags.JBYTE: - mv.visitVarInsn(ILOAD, valueIndex); - break; - case JTypeTags.JCHAR: - mv.visitVarInsn(ILOAD, valueIndex); - break; - case JTypeTags.JSHORT: - mv.visitVarInsn(ILOAD, valueIndex); - break; - case JTypeTags.JINT: - mv.visitVarInsn(ILOAD, valueIndex); - break; - case JTypeTags.JLONG: - mv.visitVarInsn(LLOAD, valueIndex); - break; - case JTypeTags.JFLOAT: - mv.visitVarInsn(FLOAD, valueIndex); - break; - case JTypeTags.JDOUBLE: - mv.visitVarInsn(DLOAD, valueIndex); - break; - case JTypeTags.JBOOLEAN: - mv.visitVarInsn(ILOAD, valueIndex); - break; - case JTypeTags.JARRAY: - case JTypeTags.JREF: - mv.visitVarInsn(ALOAD, valueIndex); - break; - default: - throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + jType); + case JTypeTags.JBYTE, JTypeTags.JSHORT, JTypeTags.JINT, JTypeTags.JBOOLEAN, JTypeTags.JCHAR -> + mv.visitVarInsn(ILOAD, valueIndex); + case JTypeTags.JLONG -> mv.visitVarInsn(LLOAD, valueIndex); + case JTypeTags.JFLOAT -> mv.visitVarInsn(FLOAD, valueIndex); + case JTypeTags.JDOUBLE -> mv.visitVarInsn(DLOAD, valueIndex); + case JTypeTags.JARRAY, JTypeTags.JREF -> mv.visitVarInsn(ALOAD, valueIndex); + default -> throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + jType); } } private void generateJVarStore(MethodVisitor mv, JType jType, int valueIndex) { switch (jType.jTag) { - case JTypeTags.JBYTE: - mv.visitVarInsn(ISTORE, valueIndex); - break; - case JTypeTags.JCHAR: - mv.visitVarInsn(ISTORE, valueIndex); - break; - case JTypeTags.JSHORT: - mv.visitVarInsn(ISTORE, valueIndex); - break; - case JTypeTags.JINT: - mv.visitVarInsn(ISTORE, valueIndex); - break; - case JTypeTags.JLONG: - mv.visitVarInsn(LSTORE, valueIndex); - break; - case JTypeTags.JFLOAT: - mv.visitVarInsn(FSTORE, valueIndex); - break; - case JTypeTags.JDOUBLE: - mv.visitVarInsn(DSTORE, valueIndex); - break; - case JTypeTags.JBOOLEAN: - mv.visitVarInsn(ISTORE, valueIndex); - break; - case JTypeTags.JARRAY: - case JTypeTags.JREF: - mv.visitVarInsn(ASTORE, valueIndex); - break; - default: - throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + jType); + case JTypeTags.JBYTE, JTypeTags.JCHAR, JTypeTags.JSHORT, JTypeTags.JINT, JTypeTags.JBOOLEAN -> + mv.visitVarInsn(ISTORE, valueIndex); + case JTypeTags.JLONG -> mv.visitVarInsn(LSTORE, valueIndex); + case JTypeTags.JFLOAT -> mv.visitVarInsn(FSTORE, valueIndex); + case JTypeTags.JDOUBLE -> mv.visitVarInsn(DSTORE, valueIndex); + case JTypeTags.JARRAY, JTypeTags.JREF -> mv.visitVarInsn(ASTORE, valueIndex); + default -> throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + jType); } } private void generateIntToUnsignedIntConversion(MethodVisitor mv, BType targetType) { targetType = JvmCodeGenUtil.getImpliedType(targetType); - switch (targetType.tag) { - case TypeTags.BYTE: // Wouldn't reach here for int atm. - case TypeTags.UNSIGNED8_INT: + switch (targetType.tag) { // Wouldn't reach here for int atm. + case TypeTags.BYTE, TypeTags.UNSIGNED8_INT -> { mv.visitInsn(L2I); mv.visitInsn(I2B); mv.visitMethodInsn(INVOKESTATIC, BYTE_VALUE, TO_UNSIGNED_LONG, "(B)J", false); - return; - case TypeTags.UNSIGNED16_INT: + } + case TypeTags.UNSIGNED16_INT -> { mv.visitInsn(L2I); mv.visitInsn(I2S); mv.visitMethodInsn(INVOKESTATIC, SHORT_VALUE, TO_UNSIGNED_LONG, "(S)J", false); - return; - case TypeTags.UNSIGNED32_INT: + } + case TypeTags.UNSIGNED32_INT -> { mv.visitInsn(L2I); mv.visitMethodInsn(INVOKESTATIC, INT_VALUE, TO_UNSIGNED_LONG, "(I)J", false); - return; + } } } @@ -451,11 +390,11 @@ public void generateVarLoad(MethodVisitor mv, BIRNode.BIRVariableDcl varDcl, int BType bType = JvmCodeGenUtil.getImpliedType(varDcl.type); switch (varDcl.kind) { - case SELF: + case SELF -> { mv.visitVarInsn(ALOAD, this.indexMap.get(OBJECT_SELF_INSTANCE)); return; - case CONSTANT: - case GLOBAL: + } + case CONSTANT, GLOBAL -> { String varName = varDcl.name.value; PackageID moduleId = ((BIRNode.BIRGlobalVariableDcl) varDcl).pkgId; String pkgName = JvmCodeGenUtil.getPackageName(moduleId); @@ -463,8 +402,9 @@ public void generateVarLoad(MethodVisitor mv, BIRNode.BIRVariableDcl varDcl, int String typeSig = getTypeDesc(bType); mv.visitFieldInsn(GETSTATIC, className, varName, typeSig); return; - default: - break; + } + default -> { + } } generateVarLoadForType(mv, bType, valueIndex); @@ -482,45 +422,20 @@ private void generateVarLoadForType (MethodVisitor mv, BType bType, int valueInd } switch (bType.tag) { - case TypeTags.BYTE: + case TypeTags.BYTE -> { mv.visitVarInsn(ILOAD, valueIndex); mv.visitInsn(I2B); mv.visitMethodInsn(INVOKESTATIC, BYTE_VALUE, JVM_TO_UNSIGNED_INT_METHOD, "(B)I", false); - break; - case TypeTags.FLOAT: - mv.visitVarInsn(DLOAD, valueIndex); - break; - case TypeTags.BOOLEAN: - mv.visitVarInsn(ILOAD, valueIndex); - break; - case TypeTags.ARRAY: - case TypeTags.MAP: - case TypeTags.STREAM: - case TypeTags.TABLE: - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.NIL: - case TypeTags.NEVER: - case TypeTags.UNION: - case TypeTags.TUPLE: - case TypeTags.RECORD: - case TypeTags.ERROR: - case TypeTags.JSON: - case TypeTags.FUTURE: - case TypeTags.OBJECT: - case TypeTags.DECIMAL: - case TypeTags.INVOKABLE: - case TypeTags.FINITE: - case TypeTags.HANDLE: - case TypeTags.TYPEDESC: - case TypeTags.READONLY: - mv.visitVarInsn(ALOAD, valueIndex); - break; - case JTypeTags.JTYPE: - generateJVarLoad(mv, (JType) bType, valueIndex); - break; - default: - throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); + } + case TypeTags.FLOAT -> mv.visitVarInsn(DLOAD, valueIndex); + case TypeTags.BOOLEAN -> mv.visitVarInsn(ILOAD, valueIndex); + case TypeTags.ARRAY, TypeTags.MAP, TypeTags.STREAM, TypeTags.TABLE, TypeTags.ANY, TypeTags.ANYDATA, + TypeTags.NIL, TypeTags.NEVER, TypeTags.UNION, TypeTags.TUPLE, TypeTags.RECORD, TypeTags.ERROR, + TypeTags.JSON, TypeTags.FUTURE, TypeTags.OBJECT, TypeTags.DECIMAL, TypeTags.INVOKABLE, + TypeTags.FINITE, TypeTags.HANDLE, TypeTags.TYPEDESC, TypeTags.READONLY -> + mv.visitVarInsn(ALOAD, valueIndex); + case JTypeTags.JTYPE -> generateJVarLoad(mv, (JType) bType, valueIndex); + default -> throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); } } @@ -552,43 +467,15 @@ private void generateVarStoreForType (MethodVisitor mv, BType bType, int valueIn } switch (bType.tag) { - case TypeTags.BYTE: - mv.visitVarInsn(ISTORE, valueIndex); - break; - case TypeTags.FLOAT: - mv.visitVarInsn(DSTORE, valueIndex); - break; - case TypeTags.BOOLEAN: - mv.visitVarInsn(ISTORE, valueIndex); - break; - case TypeTags.ARRAY: - case TypeTags.MAP: - case TypeTags.STREAM: - case TypeTags.TABLE: - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.NIL: - case TypeTags.NEVER: - case TypeTags.UNION: - case TypeTags.TUPLE: - case TypeTags.DECIMAL: - case TypeTags.RECORD: - case TypeTags.ERROR: - case TypeTags.JSON: - case TypeTags.FUTURE: - case TypeTags.OBJECT: - case TypeTags.INVOKABLE: - case TypeTags.FINITE: - case TypeTags.HANDLE: - case TypeTags.TYPEDESC: - case TypeTags.READONLY: - mv.visitVarInsn(ASTORE, valueIndex); - break; - case JTypeTags.JTYPE: - generateJVarStore(mv, (JType) bType, valueIndex); - break; - default: - throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); + case TypeTags.BYTE, TypeTags.BOOLEAN -> mv.visitVarInsn(ISTORE, valueIndex); + case TypeTags.FLOAT -> mv.visitVarInsn(DSTORE, valueIndex); + case TypeTags.ARRAY, TypeTags.MAP, TypeTags.STREAM, TypeTags.TABLE, TypeTags.ANY, TypeTags.ANYDATA, + TypeTags.NIL, TypeTags.NEVER, TypeTags.UNION, TypeTags.TUPLE, TypeTags.DECIMAL, TypeTags.RECORD, + TypeTags.ERROR, TypeTags.JSON, TypeTags.FUTURE, TypeTags.OBJECT, TypeTags.INVOKABLE, + TypeTags.FINITE, TypeTags.HANDLE, TypeTags.TYPEDESC, TypeTags.READONLY -> + mv.visitVarInsn(ASTORE, valueIndex); + case JTypeTags.JTYPE -> generateJVarStore(mv, (JType) bType, valueIndex); + default -> throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); } } @@ -616,7 +503,7 @@ private BType getSmallestBuiltInUnsignedIntSubTypeContainingTypes(BType lhsType, void generatePlatformIns(JInstruction ins, int localVarOffset) { switch (ins.jKind) { - case JCAST -> generateJCastIns((JCast) ins); + case J_CAST -> generateJCastIns((JCast) ins); case CALL -> generateJMethodCallIns(localVarOffset, (JMethodCallInstruction) ins); case LARGE_ARRAY -> generateJLargeArrayIns(localVarOffset, (JLargeArrayInstruction) ins); default -> generateJLargeMapIns(localVarOffset, (JLargeMapInstruction) ins); @@ -707,74 +594,29 @@ void generateBinaryOpIns(BIRNonTerminator.BinaryOp binaryIns) { InstructionKind insKind = binaryIns.kind; switch (insKind) { - case ADD: - this.generateAddIns(binaryIns); - break; - case SUB: - this.generateSubIns(binaryIns); - break; - case MUL: - this.generateMulIns(binaryIns); - break; - case DIV: - this.generateDivIns(binaryIns); - break; - case MOD: - this.generateRemIns(binaryIns); - break; - case EQUAL: - this.generateEqualIns(binaryIns); - break; - case NOT_EQUAL: - this.generateNotEqualIns(binaryIns); - break; - case GREATER_THAN: - this.generateGreaterThanIns(binaryIns); - break; - case GREATER_EQUAL: - this.generateGreaterEqualIns(binaryIns); - break; - case LESS_THAN: - this.generateLessThanIns(binaryIns); - break; - case LESS_EQUAL: - this.generateLessEqualIns(binaryIns); - break; - case REF_EQUAL: - this.generateRefEqualIns(binaryIns); - break; - case REF_NOT_EQUAL: - this.generateRefNotEqualIns(binaryIns); - break; - case CLOSED_RANGE: - this.generateClosedRangeIns(binaryIns); - break; - case HALF_OPEN_RANGE: - this.generateClosedRangeIns(binaryIns); - break; - case ANNOT_ACCESS: - this.generateAnnotAccessIns(binaryIns); - break; - case BITWISE_AND: - this.generateBitwiseAndIns(binaryIns); - break; - case BITWISE_OR: - this.generateBitwiseOrIns(binaryIns); - break; - case BITWISE_XOR: - this.generateBitwiseXorIns(binaryIns); - break; - case BITWISE_LEFT_SHIFT: - this.generateBitwiseLeftShiftIns(binaryIns); - break; - case BITWISE_RIGHT_SHIFT: - this.generateBitwiseRightShiftIns(binaryIns); - break; - case BITWISE_UNSIGNED_RIGHT_SHIFT: - this.generateBitwiseUnsignedRightShiftIns(binaryIns); - break; - default: - throw new BLangCompilerException("JVM generation is not supported for instruction kind : " + insKind); + case ADD -> this.generateAddIns(binaryIns); + case SUB -> this.generateSubIns(binaryIns); + case MUL -> this.generateMulIns(binaryIns); + case DIV -> this.generateDivIns(binaryIns); + case MOD -> this.generateRemIns(binaryIns); + case EQUAL -> this.generateEqualIns(binaryIns); + case NOT_EQUAL -> this.generateNotEqualIns(binaryIns); + case GREATER_THAN -> this.generateGreaterThanIns(binaryIns); + case GREATER_EQUAL -> this.generateGreaterEqualIns(binaryIns); + case LESS_THAN -> this.generateLessThanIns(binaryIns); + case LESS_EQUAL -> this.generateLessEqualIns(binaryIns); + case REF_EQUAL -> this.generateRefEqualIns(binaryIns); + case REF_NOT_EQUAL -> this.generateRefNotEqualIns(binaryIns); + case CLOSED_RANGE, HALF_OPEN_RANGE -> this.generateClosedRangeIns(binaryIns); + case ANNOT_ACCESS -> this.generateAnnotAccessIns(binaryIns); + case BITWISE_AND -> this.generateBitwiseAndIns(binaryIns); + case BITWISE_OR -> this.generateBitwiseOrIns(binaryIns); + case BITWISE_XOR -> this.generateBitwiseXorIns(binaryIns); + case BITWISE_LEFT_SHIFT -> this.generateBitwiseLeftShiftIns(binaryIns); + case BITWISE_RIGHT_SHIFT -> this.generateBitwiseRightShiftIns(binaryIns); + case BITWISE_UNSIGNED_RIGHT_SHIFT -> this.generateBitwiseUnsignedRightShiftIns(binaryIns); + default -> throw new BLangCompilerException("JVM generation is not supported " + + "for instruction kind : " + insKind); } } @@ -828,7 +670,7 @@ private void generateBinaryCompareIns(BIRNonTerminator.BinaryOp binaryIns, int o this.mv.visitJumpInsn(IF_ICMPGT, label1); } else if (opcode == IFLE) { this.mv.visitJumpInsn(IF_ICMPLE, label1); - } else if (opcode == IFGE) { + } else { this.mv.visitJumpInsn(IF_ICMPGE, label1); } } else if (lhsOpType.tag == TypeTags.BOOLEAN && rhsOpType.tag == TypeTags.BOOLEAN) { @@ -865,18 +707,13 @@ private void generateBinaryCompareIns(BIRNonTerminator.BinaryOp binaryIns, int o } private String getCompareFuncName(int opcode) { - switch (opcode) { - case IFGT: - return "compareValueGreaterThan"; - case IFGE: - return "compareValueGreaterThanOrEqual"; - case IFLT: - return "compareValueLessThan"; - case IFLE: - return "compareValueLessThanOrEqual"; - default: - throw new BLangCompilerException("Opcode: '" + opcode + "' is not a comparison opcode."); - } + return switch (opcode) { + case IFGT -> "compareValueGreaterThan"; + case IFGE -> "compareValueGreaterThanOrEqual"; + case IFLT -> "compareValueLessThan"; + case IFLE -> "compareValueLessThanOrEqual"; + default -> throw new BLangCompilerException("Opcode: '" + opcode + "' is not a comparison opcode."); + }; } private void generateEqualIns(BIRNonTerminator.BinaryOp binaryIns) { @@ -1817,7 +1654,7 @@ private void reloadObjectCtorAnnots(BType type, int strandIndex) { mv.visitMethodInsn(INVOKEVIRTUAL, OBJECT_TYPE_IMPL, "duplicate", OBJECT_TYPE_DUPLICATE, false); this.mv.visitInsn(DUP); - String pkgClassName = currentPackageName.equals(".") || currentPackageName.equals("") ? + String pkgClassName = currentPackageName.equals(".") || currentPackageName.isEmpty() ? MODULE_INIT_CLASS_NAME : jvmPackageGen.lookupGlobalVarClassName(currentPackageName, ANNOTATION_MAP_NAME); @@ -1829,35 +1666,29 @@ private void reloadObjectCtorAnnots(BType type, int strandIndex) { } void generateFPLoadIns(BIRNonTerminator.FPLoad inst) { - this.mv.visitTypeInsn(NEW, FUNCTION_POINTER); this.mv.visitInsn(DUP); - String name = inst.funcName.value; String funcKey = inst.pkgId.toString() + ":" + name; - String lambdaName = functions.get(funcKey); - if (lambdaName == null) { - lambdaName = Utils.encodeFunctionIdentifier(inst.funcName.value) + "$lambda" + - asyncDataCollector.getLambdaIndex() + "$"; - functions.put(funcKey, lambdaName); - } - asyncDataCollector.incrementLambdaIndex(); BType type = JvmCodeGenUtil.getImpliedType(inst.type); if (type.tag != TypeTags.INVOKABLE) { throw new BLangCompilerException("Expected BInvokableType, found " + type); } - for (BIROperand operand : inst.closureMaps) { if (operand != null) { this.loadVar(operand.variableDcl); } } - - JvmCodeGenUtil.visitInvokeDynamic(mv, asyncDataCollector.getEnclosingClass(), lambdaName, - inst.closureMaps.size()); + LambdaFunction lambdaFunction = functions.get(funcKey); + if (lambdaFunction == null) { + lambdaFunction = asyncDataCollector.addAndGetLambda(name, inst, false); + functions.put(funcKey, lambdaFunction); + } + JvmCodeGenUtil.visitInvokeDynamic(mv, lambdaFunction.enclosingClass, lambdaFunction.lambdaName, + inst.closureMaps.size()); // Need to remove once we fix #37875 type = inst.lhsOp.variableDcl.type.tag == TypeTags.TYPEREFDESC ? inst.lhsOp.variableDcl.type : type; @@ -1880,7 +1711,7 @@ void generateFPLoadIns(BIRNonTerminator.FPLoad inst) { String funcPkgName = JvmCodeGenUtil.getPackageName(boundMethodPkgId == null ? inst.pkgId : boundMethodPkgId); // Set annotations if available. this.mv.visitInsn(DUP); - String pkgClassName = funcPkgName.equals("") ? MODULE_INIT_CLASS_NAME : + String pkgClassName = funcPkgName.isEmpty() ? MODULE_INIT_CLASS_NAME : jvmPackageGen.lookupGlobalVarClassName(funcPkgName, ANNOTATION_MAP_NAME); this.mv.visitFieldInsn(GETSTATIC, pkgClassName, ANNOTATION_MAP_NAME, GET_MAP_VALUE); // Format of name `$anon$method$delegate$Foo.func$0`. @@ -1891,7 +1722,6 @@ void generateFPLoadIns(BIRNonTerminator.FPLoad inst) { PROCESS_FP_ANNOTATIONS, false); this.storeToVar(inst.lhsOp.variableDcl); - asyncDataCollector.add(lambdaName, inst); } private void generateRecordDefaultFPLoadIns(BIRNonTerminator.RecordDefaultFPLoad inst) { @@ -2324,162 +2154,64 @@ void generateInstructions(int localVarOffset, BIRInstruction inst) { generateBinaryOpIns((BIRNonTerminator.BinaryOp) inst); } else { switch (inst.getKind()) { - case MOVE: - generateMoveIns((BIRNonTerminator.Move) inst); - break; - case CONST_LOAD: - generateConstantLoadIns((BIRNonTerminator.ConstantLoad) inst); - break; - case NEW_STRUCTURE: - generateMapNewIns((BIRNonTerminator.NewStructure) inst, localVarOffset); - break; - case NEW_INSTANCE: - generateObjectNewIns((BIRNonTerminator.NewInstance) inst, localVarOffset); - break; - case MAP_STORE: - generateMapStoreIns((FieldAccess) inst); - break; - case NEW_TABLE: - generateTableNewIns((NewTable) inst); - break; - case TABLE_STORE: - generateTableStoreIns((FieldAccess) inst); - break; - case TABLE_LOAD: - generateTableLoadIns((FieldAccess) inst); - break; - case NEW_ARRAY: - generateArrayNewIns((BIRNonTerminator.NewArray) inst, localVarOffset); - break; - case ARRAY_STORE: - generateArrayStoreIns((FieldAccess) inst); - break; - case MAP_LOAD: - generateMapLoadIns((FieldAccess) inst); - break; - case ARRAY_LOAD: - generateArrayValueLoad((FieldAccess) inst); - break; - case NEW_ERROR: - generateNewErrorIns((BIRNonTerminator.NewError) inst); - break; - case TYPE_CAST: - generateCastIns((BIRNonTerminator.TypeCast) inst); - break; - case IS_LIKE: - generateIsLikeIns((BIRNonTerminator.IsLike) inst); - break; - case TYPE_TEST: - typeTestGen.generateTypeTestIns((BIRNonTerminator.TypeTest) inst); - break; - case OBJECT_STORE: - generateObjectStoreIns((FieldAccess) inst); - break; - case OBJECT_LOAD: - generateObjectLoadIns((FieldAccess) inst); - break; - case NEW_XML_ELEMENT: - generateNewXMLElementIns((BIRNonTerminator.NewXMLElement) inst); - break; - case NEW_XML_TEXT: - generateNewXMLTextIns((BIRNonTerminator.NewXMLText) inst); - break; - case NEW_XML_COMMENT: - generateNewXMLCommentIns((BIRNonTerminator.NewXMLComment) inst); - break; - case NEW_XML_PI: - generateNewXMLProcIns((BIRNonTerminator.NewXMLProcIns) inst); - break; - case NEW_XML_QNAME: - generateNewXMLQNameIns((BIRNonTerminator.NewXMLQName) inst); - break; - case NEW_STRING_XML_QNAME: - generateNewStringXMLQNameIns((BIRNonTerminator.NewStringXMLQName) inst); - break; - case NEW_XML_SEQUENCE: - generateNewXMLSequenceIns((BIRNonTerminator.NewXMLSequence) inst); - break; - case XML_SEQ_STORE: - generateXMLStoreIns((BIRNonTerminator.XMLAccess) inst); - break; - case XML_SEQ_LOAD: - case XML_LOAD: - generateXMLLoadIns((FieldAccess) inst); - break; - case XML_LOAD_ALL: - generateXMLLoadAllIns((BIRNonTerminator.XMLAccess) inst); - break; - case XML_ATTRIBUTE_STORE: - generateXMLAttrStoreIns((FieldAccess) inst); - break; - case XML_ATTRIBUTE_LOAD: - generateXMLAttrLoadIns((FieldAccess) inst); - break; - case NEW_REG_EXP: - generateNewRegExpIns((BIRNonTerminator.NewRegExp) inst); - break; - case NEW_RE_DISJUNCTION: - generateNewRegExpDisjunctionIns((BIRNonTerminator.NewReDisjunction) inst); - break; - case NEW_RE_SEQUENCE: - generateNewRegExpSequenceIns((BIRNonTerminator.NewReSequence) inst); - break; - case NEW_RE_ASSERTION: - generateNewRegExpAssertionIns((BIRNonTerminator.NewReAssertion) inst); - break; - case NEW_RE_ATOM_QUANTIFIER: - generateNewRegExpAtomQuantifierIns((BIRNonTerminator.NewReAtomQuantifier) inst); - break; - case NEW_RE_LITERAL_CHAR_ESCAPE: - generateNewRegExpLiteralCharOrEscapeIns((BIRNonTerminator.NewReLiteralCharOrEscape) inst); - break; - case NEW_RE_CHAR_CLASS: - generateNewRegExpCharacterClassIns((BIRNonTerminator.NewReCharacterClass) inst); - break; - case NEW_RE_CHAR_SET: - generateNewRegExpCharSetIns((BIRNonTerminator.NewReCharSet) inst); - break; - case NEW_RE_CHAR_SET_RANGE: - generateNewRegExpCharSetRangeIns((BIRNonTerminator.NewReCharSetRange) inst); - break; - case NEW_RE_CAPTURING_GROUP: - generateNewRegExpCapturingGroupIns((BIRNonTerminator.NewReCapturingGroup) inst); - break; - case NEW_RE_FLAG_EXPR: - generateNewRegExpFlagExprIns((BIRNonTerminator.NewReFlagExpression) inst); - break; - case NEW_RE_FLAG_ON_OFF: - generateNewRegExpFlagOnOffIns((BIRNonTerminator.NewReFlagOnOff) inst); - break; - case NEW_RE_QUANTIFIER: - generateNewRegExpQuantifierIns((BIRNonTerminator.NewReQuantifier) inst); - break; - case FP_LOAD: - generateFPLoadIns((BIRNonTerminator.FPLoad) inst); - break; - case STRING_LOAD: - generateStringLoadIns((FieldAccess) inst); - break; - case TYPEOF: - generateTypeofIns((BIRNonTerminator.UnaryOP) inst); - break; - case NOT: - generateNotIns((BIRNonTerminator.UnaryOP) inst); - break; - case NEW_TYPEDESC: - generateNewTypedescIns((BIRNonTerminator.NewTypeDesc) inst); - break; - case NEGATE: - generateNegateIns((BIRNonTerminator.UnaryOP) inst); - break; - case PLATFORM: - generatePlatformIns((JInstruction) inst, localVarOffset); - break; - case RECORD_DEFAULT_FP_LOAD: - generateRecordDefaultFPLoadIns((BIRNonTerminator.RecordDefaultFPLoad) inst); - break; - default: - throw new BLangCompilerException("JVM generation is not supported for operation " + inst); + case MOVE -> generateMoveIns((BIRNonTerminator.Move) inst); + case CONST_LOAD -> generateConstantLoadIns((BIRNonTerminator.ConstantLoad) inst); + case NEW_STRUCTURE -> generateMapNewIns((BIRNonTerminator.NewStructure) inst, localVarOffset); + case NEW_INSTANCE -> generateObjectNewIns((BIRNonTerminator.NewInstance) inst, localVarOffset); + case MAP_STORE -> generateMapStoreIns((FieldAccess) inst); + case NEW_TABLE -> generateTableNewIns((NewTable) inst); + case TABLE_STORE -> generateTableStoreIns((FieldAccess) inst); + case TABLE_LOAD -> generateTableLoadIns((FieldAccess) inst); + case NEW_ARRAY -> generateArrayNewIns((BIRNonTerminator.NewArray) inst, localVarOffset); + case ARRAY_STORE -> generateArrayStoreIns((FieldAccess) inst); + case MAP_LOAD -> generateMapLoadIns((FieldAccess) inst); + case ARRAY_LOAD -> generateArrayValueLoad((FieldAccess) inst); + case NEW_ERROR -> generateNewErrorIns((BIRNonTerminator.NewError) inst); + case TYPE_CAST -> generateCastIns((BIRNonTerminator.TypeCast) inst); + case IS_LIKE -> generateIsLikeIns((BIRNonTerminator.IsLike) inst); + case TYPE_TEST -> typeTestGen.generateTypeTestIns((BIRNonTerminator.TypeTest) inst); + case OBJECT_STORE -> generateObjectStoreIns((FieldAccess) inst); + case OBJECT_LOAD -> generateObjectLoadIns((FieldAccess) inst); + case NEW_XML_ELEMENT -> generateNewXMLElementIns((BIRNonTerminator.NewXMLElement) inst); + case NEW_XML_TEXT -> generateNewXMLTextIns((BIRNonTerminator.NewXMLText) inst); + case NEW_XML_COMMENT -> generateNewXMLCommentIns((BIRNonTerminator.NewXMLComment) inst); + case NEW_XML_PI -> generateNewXMLProcIns((BIRNonTerminator.NewXMLProcIns) inst); + case NEW_XML_QNAME -> generateNewXMLQNameIns((BIRNonTerminator.NewXMLQName) inst); + case NEW_STRING_XML_QNAME -> generateNewStringXMLQNameIns((BIRNonTerminator.NewStringXMLQName) inst); + case NEW_XML_SEQUENCE -> generateNewXMLSequenceIns((BIRNonTerminator.NewXMLSequence) inst); + case XML_SEQ_STORE -> generateXMLStoreIns((BIRNonTerminator.XMLAccess) inst); + case XML_SEQ_LOAD, XML_LOAD -> generateXMLLoadIns((FieldAccess) inst); + case XML_LOAD_ALL -> generateXMLLoadAllIns((BIRNonTerminator.XMLAccess) inst); + case XML_ATTRIBUTE_STORE -> generateXMLAttrStoreIns((FieldAccess) inst); + case XML_ATTRIBUTE_LOAD -> generateXMLAttrLoadIns((FieldAccess) inst); + case NEW_REG_EXP -> generateNewRegExpIns((BIRNonTerminator.NewRegExp) inst); + case NEW_RE_DISJUNCTION -> generateNewRegExpDisjunctionIns((BIRNonTerminator.NewReDisjunction) inst); + case NEW_RE_SEQUENCE -> generateNewRegExpSequenceIns((BIRNonTerminator.NewReSequence) inst); + case NEW_RE_ASSERTION -> generateNewRegExpAssertionIns((BIRNonTerminator.NewReAssertion) inst); + case NEW_RE_ATOM_QUANTIFIER -> + generateNewRegExpAtomQuantifierIns((BIRNonTerminator.NewReAtomQuantifier) inst); + case NEW_RE_LITERAL_CHAR_ESCAPE -> + generateNewRegExpLiteralCharOrEscapeIns((BIRNonTerminator.NewReLiteralCharOrEscape) inst); + case NEW_RE_CHAR_CLASS -> + generateNewRegExpCharacterClassIns((BIRNonTerminator.NewReCharacterClass) inst); + case NEW_RE_CHAR_SET -> generateNewRegExpCharSetIns((BIRNonTerminator.NewReCharSet) inst); + case NEW_RE_CHAR_SET_RANGE -> + generateNewRegExpCharSetRangeIns((BIRNonTerminator.NewReCharSetRange) inst); + case NEW_RE_CAPTURING_GROUP -> + generateNewRegExpCapturingGroupIns((BIRNonTerminator.NewReCapturingGroup) inst); + case NEW_RE_FLAG_EXPR -> generateNewRegExpFlagExprIns((BIRNonTerminator.NewReFlagExpression) inst); + case NEW_RE_FLAG_ON_OFF -> generateNewRegExpFlagOnOffIns((BIRNonTerminator.NewReFlagOnOff) inst); + case NEW_RE_QUANTIFIER -> generateNewRegExpQuantifierIns((BIRNonTerminator.NewReQuantifier) inst); + case FP_LOAD -> generateFPLoadIns((BIRNonTerminator.FPLoad) inst); + case STRING_LOAD -> generateStringLoadIns((FieldAccess) inst); + case TYPEOF -> generateTypeofIns((BIRNonTerminator.UnaryOP) inst); + case NOT -> generateNotIns((BIRNonTerminator.UnaryOP) inst); + case NEW_TYPEDESC -> generateNewTypedescIns((BIRNonTerminator.NewTypeDesc) inst); + case NEGATE -> generateNegateIns((BIRNonTerminator.UnaryOP) inst); + case PLATFORM -> generatePlatformIns((JInstruction) inst, localVarOffset); + case RECORD_DEFAULT_FP_LOAD -> + generateRecordDefaultFPLoadIns((BIRNonTerminator.RecordDefaultFPLoad) inst); + default -> throw new BLangCompilerException("JVM generation is not supported for operation " + inst); } } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmObservabilityGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmObservabilityGen.java index 50bbc03570d3..8802fa06e368 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmObservabilityGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmObservabilityGen.java @@ -24,8 +24,8 @@ import org.ballerinalang.model.elements.PackageID; import org.ballerinalang.model.symbols.SymbolKind; import org.wso2.ballerinalang.compiler.PackageCache; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JIMethodCall; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JMethodCallInstruction; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JIMethodCall; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JMethodCallInstruction; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; import org.wso2.ballerinalang.compiler.bir.model.BIRNode.BIRAnnotationAttachment; import org.wso2.ballerinalang.compiler.bir.model.BIRNode.BIRBasicBlock; @@ -986,8 +986,7 @@ private boolean isObservable(Call callIns) { */ private boolean isErrorAssignable(BIRVariableDcl variableDcl) { boolean isErrorAssignable = false; - if (variableDcl.type instanceof BUnionType) { - BUnionType returnUnionType = (BUnionType) variableDcl.type; + if (variableDcl.type instanceof BUnionType returnUnionType) { boolean b = false; for (BType type : returnUnionType.getMemberTypes()) { if (type instanceof BErrorType) { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmPackageGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmPackageGen.java index a82af2f48f9e..f6316475a157 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmPackageGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmPackageGen.java @@ -28,12 +28,10 @@ import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodTooLargeException; import org.objectweb.asm.MethodVisitor; -import org.wso2.ballerinalang.compiler.CompiledJarFile; import org.wso2.ballerinalang.compiler.PackageCache; +import org.wso2.ballerinalang.compiler.bir.codegen.exceptions.JInteropException; import org.wso2.ballerinalang.compiler.bir.codegen.internal.AsyncDataCollector; import org.wso2.ballerinalang.compiler.bir.codegen.internal.JavaClass; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.BIRFunctionWrapper; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JInteropException; import org.wso2.ballerinalang.compiler.bir.codegen.methodgen.ConfigMethodGen; import org.wso2.ballerinalang.compiler.bir.codegen.methodgen.FrameClassGen; import org.wso2.ballerinalang.compiler.bir.codegen.methodgen.InitMethodGen; @@ -42,9 +40,9 @@ import org.wso2.ballerinalang.compiler.bir.codegen.methodgen.MethodGen; import org.wso2.ballerinalang.compiler.bir.codegen.methodgen.MethodGenUtils; import org.wso2.ballerinalang.compiler.bir.codegen.methodgen.ModuleStopMethodGen; +import org.wso2.ballerinalang.compiler.bir.codegen.model.BIRFunctionWrapper; import org.wso2.ballerinalang.compiler.bir.codegen.split.JvmConstantsGen; import org.wso2.ballerinalang.compiler.bir.codegen.split.JvmMethodsSplitter; -import org.wso2.ballerinalang.compiler.bir.model.BIRInstruction; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; import org.wso2.ballerinalang.compiler.bir.model.BIRNode.BIRFunction; import org.wso2.ballerinalang.compiler.bir.model.BIRNode.BIRGlobalVariableDcl; @@ -111,12 +109,16 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.LOCK_STORE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.LOCK_STORE_VAR_NAME; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MAIN_METHOD; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MAX_GENERATED_METHODS_PER_CLASS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_EXECUTE_METHOD; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_GENERATED_FUNCTIONS_CLASS_NAME; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_INIT_CLASS_NAME; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_STARTED; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_START_ATTEMPTED; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.PARENT_MODULE_START_ATTEMPTED; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_STOP_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_TYPES_CLASS_NAME; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.NO_OF_DEPENDANT_MODULES; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.OBJECT; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.SERVICE_EP_AVAILABLE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.TEST_EXECUTE_METHOD; @@ -146,7 +148,6 @@ public class JvmPackageGen { private final ConfigMethodGen configMethodGen; private final Map birFunctionMap; private final Map globalVarClassMap; - private final Set dependentModules; private final BLangDiagnosticLog dlog; private final Types types; private final boolean isRemoteMgtEnabled; @@ -155,7 +156,6 @@ public class JvmPackageGen { boolean isRemoteMgtEnabled) { birFunctionMap = new HashMap<>(); globalVarClassMap = new HashMap<>(); - dependentModules = new LinkedHashSet<>(); this.symbolTable = symbolTable; this.packageCache = packageCache; this.dlog = dlog; @@ -243,20 +243,16 @@ private static void generateLockForVariable(ClassWriter cw) { private static void generateStaticInitializer(ClassWriter cw, String className, BIRPackage birPackage, boolean isInitClass, boolean serviceEPAvailable, - AsyncDataCollector asyncDataCollector, JvmConstantsGen jvmConstantsGen) { - if (!isInitClass && asyncDataCollector.getStrandMetadata().isEmpty()) { + if (!isInitClass) { return; } MethodVisitor mv = cw.visitMethod(ACC_STATIC, JVM_STATIC_INIT_METHOD, VOID_METHOD_DESC, null, null); - if (isInitClass) { - setConstantFields(mv, birPackage, jvmConstantsGen); - setLockStoreField(mv, className); - setServiceEPAvailableField(cw, mv, serviceEPAvailable, className); - setModuleStatusField(cw, mv, className); - setCurrentModuleField(cw, mv, jvmConstantsGen, birPackage.packageID, className); - } - JvmCodeGenUtil.generateStrandMetadata(mv, className, birPackage.packageID, asyncDataCollector); + setConstantFields(mv, birPackage, jvmConstantsGen); + setLockStoreField(mv, className); + setServiceEPAvailableField(cw, mv, serviceEPAvailable, className); + setModuleStatusField(cw, mv, className); + setCurrentModuleField(cw, mv, jvmConstantsGen, birPackage.packageID, className); mv.visitInsn(RETURN); JvmCodeGenUtil.visitMaxStackForMethod(mv, JVM_STATIC_INIT_METHOD, className); mv.visitEnd(); @@ -304,6 +300,15 @@ private static void setModuleStatusField(ClassWriter cw, MethodVisitor mv, Strin mv.visitInsn(ICONST_0); mv.visitFieldInsn(PUTSTATIC, initClass, MODULE_STARTED, "Z"); + + fv = cw.visitField(ACC_PUBLIC + ACC_STATIC, PARENT_MODULE_START_ATTEMPTED, "Z", null, null); + fv.visitEnd(); + mv.visitInsn(ICONST_0); + mv.visitFieldInsn(PUTSTATIC, initClass, PARENT_MODULE_START_ATTEMPTED, "Z"); + fv = cw.visitField(ACC_PUBLIC + ACC_STATIC, NO_OF_DEPENDANT_MODULES, "I", null, null); + fv.visitEnd(); + mv.visitInsn(ICONST_0); + mv.visitFieldInsn(PUTSTATIC, initClass, NO_OF_DEPENDANT_MODULES, "I"); } private static void setCurrentModuleField(ClassWriter cw, MethodVisitor mv, JvmConstantsGen jvmConstantsGen, @@ -343,11 +348,9 @@ public static BIRFunctionWrapper getFunctionWrapper(BIRFunction currentFunc, Pac private static BIRFunction findFunction(BIRNode parentNode, String funcName) { BIRFunction func; - if (parentNode instanceof BIRTypeDefinition) { - BIRTypeDefinition typeDef = (BIRTypeDefinition) parentNode; + if (parentNode instanceof BIRTypeDefinition typeDef) { func = findFunction(typeDef.attachedFuncs, funcName); - } else if (parentNode instanceof BIRPackage) { - BIRPackage pkg = (BIRPackage) parentNode; + } else if (parentNode instanceof BIRPackage pkg) { func = findFunction(pkg.functions, funcName); } else { // some generated functions will not have bir function @@ -367,17 +370,17 @@ private static BIRFunction findFunction(List functions, String func return null; } - private void generateModuleClasses(BIRPackage module, Map jarEntries, - String moduleInitClass, String typesClass, - JvmTypeGen jvmTypeGen, JvmCastGen jvmCastGen, JvmConstantsGen jvmConstantsGen, - Map jvmClassMapping, List moduleImports, - boolean serviceEPAvailable, BIRFunction mainFunc, BIRFunction testExecuteFunc) { + private void generateModuleClasses(BIRPackage module, JarEntries jarEntries, String moduleInitClass, + String typesClass, JvmTypeGen jvmTypeGen, JvmCastGen jvmCastGen, + JvmConstantsGen jvmConstantsGen, Map jvmClassMapping, + boolean serviceEPAvailable, BIRFunction mainFunc, BIRFunction testExecuteFunc, + AsyncDataCollector asyncDataCollector, Set immediateImports) { jvmClassMapping.forEach((moduleClass, javaClass) -> { ClassWriter cw = new BallerinaClassWriter(COMPUTE_FRAMES); - AsyncDataCollector asyncDataCollector = new AsyncDataCollector(moduleClass); + asyncDataCollector.setCurrentSourceFileName(javaClass.sourceFileName); + asyncDataCollector.setCurrentSourceFileWithoutExt(javaClass.cleanedBalFileName); boolean isInitClass = Objects.equals(moduleClass, moduleInitClass); boolean isTestable = testExecuteFunc != null; - LambdaGen lambdaGen = new LambdaGen(this, jvmCastGen); if (isInitClass) { cw.visit(V17, ACC_PUBLIC + ACC_SUPER, moduleClass, null, VALUE_CREATOR, null); JvmCodeGenUtil.generateDefaultConstructor(cw, VALUE_CREATOR); @@ -391,12 +394,12 @@ private void generateModuleClasses(BIRPackage module, Map jarEnt } } - MainMethodGen mainMethodGen = new MainMethodGen(symbolTable, jvmTypeGen, asyncDataCollector, - isRemoteMgtEnabled); + MainMethodGen mainMethodGen = new MainMethodGen(symbolTable, jvmTypeGen, jvmConstantsGen, + asyncDataCollector, isRemoteMgtEnabled); mainMethodGen.generateMainMethod(mainFunc, cw, module, moduleClass, serviceEPAvailable, isTestable); initMethodGen.generateLambdaForModuleExecuteFunction(cw, moduleClass, jvmCastGen, mainFunc, testExecuteFunc); - initMethodGen.generateLambdaForPackageInits(cw, module, moduleClass, moduleImports); + initMethodGen.generateLambdaForPackageInit(cw, module, moduleClass); initMethodGen.generateGracefulExitMethod(cw); if (isTestable) { initMethodGen.generateGetTestExecutionState(cw, moduleClass); @@ -404,9 +407,10 @@ private void generateModuleClasses(BIRPackage module, Map jarEnt generateLockForVariable(cw); initMethodGen.generateModuleInitializer(cw, module, moduleInitClass, typesClass); - ModuleStopMethodGen moduleStopMethodGen = new ModuleStopMethodGen(symbolTable, jvmTypeGen); - moduleStopMethodGen.generateExecutionStopMethod(cw, moduleInitClass, module, moduleImports, - asyncDataCollector); + initMethodGen.generateModuleStop(cw, moduleInitClass, asyncDataCollector, jvmConstantsGen); + ModuleStopMethodGen stopMethodGen = new ModuleStopMethodGen(jvmTypeGen, jvmConstantsGen); + stopMethodGen.generateExecutionStopMethod(cw, moduleInitClass, module, asyncDataCollector, + immediateImports); } else { cw.visit(V17, ACC_PUBLIC + ACC_SUPER, moduleClass, null, OBJECT, null); JvmCodeGenUtil.generateDefaultConstructor(cw, OBJECT); @@ -417,15 +421,8 @@ private void generateModuleClasses(BIRPackage module, Map jarEnt methodGen.generateMethod(func, cw, module, null, moduleClass, jvmTypeGen, jvmCastGen, jvmConstantsGen, asyncDataCollector); } - // generate lambdas created during generating methods - for (Map.Entry lambda : asyncDataCollector.getLambdas().entrySet()) { - String name = lambda.getKey(); - BIRInstruction call = lambda.getValue(); - lambdaGen.generateLambdaMethod(call, cw, name, moduleClass); - } - JvmCodeGenUtil.visitStrandMetadataFields(cw, asyncDataCollector.getStrandMetadata()); generateStaticInitializer(cw, moduleClass, module, isInitClass, serviceEPAvailable, - asyncDataCollector, jvmConstantsGen); + jvmConstantsGen); cw.visitEnd(); byte[] bytes = getBytes(cw, module); @@ -433,11 +430,6 @@ private void generateModuleClasses(BIRPackage module, Map jarEnt }); } - private List flattenModuleImports(Set dependentModuleArray) { - dependentModuleArray.addAll(dependentModules); - return new ArrayList<>(dependentModuleArray); - } - /** * Java Class will be generated for each source file. This method add class mappings to globalVar and filters the * functions based on their source file name and then returns map of associated java class contents. @@ -542,7 +534,8 @@ private void linkModuleFunctions(BIRPackage birPackage, String initClass, boolea // function. BIRFunction initFunc = functions.get(0); String functionName = Utils.encodeFunctionIdentifier(initFunc.name.value); - JavaClass klass = new JavaClass(initFunc.pos.lineRange().fileName()); + String fileName = initFunc.pos.lineRange().fileName(); + JavaClass klass = new JavaClass(fileName, fileName); klass.functions.add(0, initFunc); PackageID packageID = birPackage.packageID; jvmClassMap.put(initClass, klass); @@ -563,6 +556,8 @@ private void linkModuleFunctions(BIRPackage birPackage, String initClass, boolea birFunctionMap.put(pkgName + functionName, getFunctionWrapper(stopFunc, packageID, initClass)); klass.functions.add(2, stopFunc); count += 1; + int genMethodsCount = 0; + int genClassNum = 0; // Generate classes for other functions. while (count < funcSize) { @@ -571,8 +566,16 @@ private void linkModuleFunctions(BIRPackage birPackage, String initClass, boolea // link the bir function for lookup String birFuncName = birFunc.name.value; String balFileName; - if (birFunc.pos == null || birFunc.pos == symbolTable.builtinPos) { + if (birFunc.pos == symbolTable.builtinPos) { balFileName = MODULE_INIT_CLASS_NAME; + } else if (birFunc.pos == null) { + balFileName = MODULE_GENERATED_FUNCTIONS_CLASS_NAME + genClassNum; + if (genMethodsCount > MAX_GENERATED_METHODS_PER_CLASS) { + genMethodsCount = 0; + genClassNum++; + } else { + genMethodsCount++; + } } else { balFileName = birFunc.pos.lineRange().fileName(); } @@ -590,7 +593,7 @@ private void linkModuleFunctions(BIRPackage birPackage, String initClass, boolea if (javaClass != null) { javaClass.functions.add(birFunc); } else { - klass = new JavaClass(balFileName); + klass = new JavaClass(balFileName, cleanedBalFileName); klass.functions.add(0, birFunc); jvmClassMap.put(birModuleClassName, klass); } @@ -609,7 +612,7 @@ private BIRFunctionWrapper getBirFunctionWrapper(boolean isEntry, PackageID pack BIRFunction birFunc, String birModuleClassName) { BIRFunctionWrapper birFuncWrapperOrError; if (isExternFunc(birFunc) && isEntry) { - birFuncWrapperOrError = createExternalFunctionWrapper(isEntry, birFunc, packageID, birModuleClassName); + birFuncWrapperOrError = createExternalFunctionWrapper(true, birFunc, packageID, birModuleClassName); } else { if (isEntry && birFunc.receiver == null) { addDefaultableBooleanVarsToSignature(birFunc); @@ -649,7 +652,6 @@ public byte[] getBytes(ClassWriter cw, BIRNode node) { private void clearPackageGenInfo() { birFunctionMap.clear(); globalVarClassMap.clear(); - dependentModules.clear(); } public BIRFunctionWrapper lookupBIRFunctionWrapper(String lookupKey) { @@ -693,68 +695,57 @@ public String lookupGlobalVarClassName(String pkgName, String varName) { } } - private void generateDependencyList(BPackageSymbol packageSymbol) { - if (packageSymbol.bir != null) { - generate(packageSymbol.bir, false); - } else { - for (BPackageSymbol importPkgSymbol : packageSymbol.imports) { - if (importPkgSymbol == null) { - continue; - } - generateDependencyList(importPkgSymbol); - } - } - dependentModules.add(packageSymbol.pkgID); - } - - CompiledJarFile generate(BIRPackage module, boolean isEntry) { - if (dependentModules.contains(module.packageID)) { - return null; - } - Set moduleImports = new LinkedHashSet<>(); - addBuiltinImports(module.packageID, moduleImports); + CompiledJarFile generate(BIRPackage module) { boolean serviceEPAvailable = module.isListenerAvailable; for (BIRNode.BIRImportModule importModule : module.importModules) { - BPackageSymbol pkgSymbol = packageCache.getSymbol( getBvmAlias(importModule.packageID.orgName.value, importModule.packageID.name.value)); - generateDependencyList(pkgSymbol); + if (pkgSymbol.bir != null) { + String moduleInitClass = + JvmCodeGenUtil.getModuleLevelClassName(pkgSymbol.bir.packageID, MODULE_INIT_CLASS_NAME); + generateClassNameLinking(pkgSymbol.bir, moduleInitClass, false); + } serviceEPAvailable |= listenerDeclarationFound(pkgSymbol); } String moduleInitClass = JvmCodeGenUtil.getModuleLevelClassName(module.packageID, MODULE_INIT_CLASS_NAME); String typesClass = getModuleLevelClassName(module.packageID, MODULE_TYPES_CLASS_NAME); - Map jvmClassMapping = generateClassNameLinking(module, moduleInitClass, isEntry); - - if (!isEntry) { - return null; - } - - // use a map to store class byte values - final Map jarEntries = new HashMap<>(); + Map jvmClassMapping = generateClassNameLinking(module, moduleInitClass, true); + CompiledJarFile compiledJarFile = new CompiledJarFile( + getModuleLevelClassName(module.packageID, MODULE_INIT_CLASS_NAME, ".")); + // use a ByteArrayOutputStream to store class byte values + final JarEntries jarEntries = compiledJarFile.jarEntries; // desugar parameter initialization injectDefaultParamInits(module, initMethodGen); - injectDefaultParamInitsToAttachedFuncs(module, initMethodGen, this); - - // create imported modules flat list - List flattenedModuleImports = flattenModuleImports(moduleImports); + injectDefaultParamInitsToAttachedFuncs(module, initMethodGen); BIRFunction mainFunc = getMainFunction(module); BIRFunction testExecuteFunc = getTestExecuteFunction(module); + // Getting the non-duplicate immediateImports + Set immediateImports = new LinkedHashSet<>(); + addBuiltinImports(module.packageID, immediateImports); + for (BIRNode.BIRImportModule immediateImport : module.importModules) { + BPackageSymbol pkgSymbol = packageCache.getSymbol( + getBvmAlias(immediateImport.packageID.orgName.value, immediateImport.packageID.name.value)); + immediateImports.add(pkgSymbol.pkgID); + } + // enrich current package with package initializers initMethodGen.enrichPkgWithInitializers(birFunctionMap, jvmClassMapping, moduleInitClass, module, - flattenedModuleImports, serviceEPAvailable, mainFunc, testExecuteFunc); + immediateImports, serviceEPAvailable, mainFunc, testExecuteFunc); TypeHashVisitor typeHashVisitor = new TypeHashVisitor(); + AsyncDataCollector asyncDataCollector = new AsyncDataCollector(module); JvmConstantsGen jvmConstantsGen = new JvmConstantsGen(module, moduleInitClass, types, typeHashVisitor); JvmTypeGen jvmTypeGen = new JvmTypeGen(jvmConstantsGen, module.packageID, typeHashVisitor, symbolTable); JvmMethodsSplitter jvmMethodsSplitter = new JvmMethodsSplitter(this, jvmConstantsGen, module, moduleInitClass, typeHashVisitor, jvmTypeGen); - configMethodGen.generateConfigMapper(flattenedModuleImports, module, moduleInitClass, jvmConstantsGen, + configMethodGen.generateConfigMapper(immediateImports, module, moduleInitClass, jvmConstantsGen, typeHashVisitor, jarEntries, symbolTable); // generate the shutdown listener class. - new ShutDownListenerGen().generateShutdownSignalListener(moduleInitClass, jarEntries); + new ShutDownListenerGen().generateShutdownSignalListener(moduleInitClass, jarEntries + ); removeSourceAnnotationTypeDefs(module.typeDefs); // desugar the record init function @@ -763,24 +754,26 @@ CompiledJarFile generate(BIRPackage module, boolean isEntry) { // generate object/record value classes JvmValueGen valueGen = new JvmValueGen(module, this, methodGen, typeHashVisitor, types); JvmCastGen jvmCastGen = new JvmCastGen(symbolTable, jvmTypeGen, types); - valueGen.generateValueClasses(jarEntries, jvmConstantsGen, jvmTypeGen); + LambdaGen lambdaGen = new LambdaGen(this, jvmCastGen, module); + valueGen.generateValueClasses(jarEntries, jvmConstantsGen, jvmTypeGen, asyncDataCollector); // generate frame classes frameClassGen.generateFrameClasses(module, jarEntries); // generate module classes generateModuleClasses(module, jarEntries, moduleInitClass, typesClass, jvmTypeGen, jvmCastGen, jvmConstantsGen, - jvmClassMapping, flattenedModuleImports, serviceEPAvailable, mainFunc, testExecuteFunc); + jvmClassMapping, serviceEPAvailable, mainFunc, testExecuteFunc, asyncDataCollector, immediateImports); List sortedFunctions = new ArrayList<>(module.functions); sortedFunctions.sort(NAME_HASH_COMPARATOR); - jvmMethodsSplitter.generateMethods(jarEntries, jvmCastGen, sortedFunctions); - jvmConstantsGen.generateConstants(jarEntries); + jvmMethodsSplitter.generateMethods(jarEntries, jvmCastGen, sortedFunctions, asyncDataCollector); + jvmConstantsGen.generateConstants(jarEntries, asyncDataCollector.getStrandMetadata()); + lambdaGen.generateLambdaClasses(asyncDataCollector, jarEntries); // clear class name mappings clearPackageGenInfo(); - return new CompiledJarFile(getModuleLevelClassName(module.packageID, MODULE_INIT_CLASS_NAME, "."), jarEntries); + return compiledJarFile; } private void removeSourceAnnotationTypeDefs(List typeDefs) { @@ -822,8 +815,8 @@ private boolean listenerDeclarationFound(BPackageSymbol packageSymbol) { return true; } } - } else if (packageSymbol.bir.isListenerAvailable) { - return true; + } else { + return packageSymbol.bir.isListenerAvailable; } for (BPackageSymbol importPkgSymbol : packageSymbol.imports) { if (importPkgSymbol != null && listenerDeclarationFound(importPkgSymbol)) { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmSignatures.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmSignatures.java index 356149014add..69ece2dae70f 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmSignatures.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmSignatures.java @@ -25,7 +25,6 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.ARRAY_VALUE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.BAL_ENV; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.BERROR; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.BIG_DECIMAL; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.BOOLEAN_TYPE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.BOOLEAN_VALUE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.BYTE_TYPE; @@ -134,7 +133,7 @@ * * @since 1.2.0 */ -public class JvmSignatures { +public final class JvmSignatures { public static final String INIT_ERROR_WITH_TYPE = "(L" + TYPE + ";L" + B_STRING_VALUE + ";L" + BERROR + ";L" + OBJECT + ";)V"; @@ -161,7 +160,6 @@ public class JvmSignatures { public static final String ARRAY_ADD_BSTRING = "(JL" + JvmConstants.B_STRING_VALUE + ";)V"; public static final String ARRAY_ADD_OBJECT = "(JL" + OBJECT + ";)V"; public static final String BAL_ENV_PARAM = "(L" + BAL_ENV + ";"; - public static final String BBB = "(L" + STRING_VALUE + ";)L" + OBJECT + ";"; public static final String BOBJECT_CALL = "(L" + STRAND_CLASS + ";L" + STRING_VALUE + ";[L" + OBJECT + ";)L" + OBJECT + ";"; public static final String BOBJECT_GET = "(L" + B_STRING_VALUE + ";)L" + OBJECT + ";"; @@ -194,6 +192,7 @@ public class JvmSignatures { public static final String CREATE_XML_PI = "(L" + B_STRING_VALUE + ";L" + B_STRING_VALUE + ";Z)L" + XML_VALUE + ";"; public static final String CREATE_XML_TEXT = "(L" + B_STRING_VALUE + ";)L" + XML_VALUE + ";"; public static final String CRETAE_XML_SEQUENCE = "()L" + XML_SEQUENCE + ";"; + public static final String CURRENT_MODULE_STOP = "(L" + RUNTIME_REGISTRY_CLASS + ";)V"; public static final String DECIMAL_NEGATE = "()L" + DECIMAL_VALUE + ";"; public static final String DECIMAL_TO_HANDLE = "(L" + OBJECT + ";)L" + HANDLE_VALUE + ";"; public static final String DECIMAL_VALUE_OF_BOOLEAN = "(B)L" + DECIMAL_VALUE + ";"; @@ -253,7 +252,9 @@ public class JvmSignatures { public static final String GET_STRING = "L" + STRING_VALUE + ";"; public static final String GET_STRING_AT = "(L" + B_STRING_VALUE + ";J)L" + B_STRING_VALUE + ";"; public static final String GET_STRING_FROM_ARRAY = "(J)L" + OBJECT + ";"; + public static final String GET_PATH = "[L" + PATH + ";"; public static final String GET_TABLE_VALUE = "L" + TABLE_VALUE + ";"; + public static final String GET_JBOOLEAN_TYPE = "Z"; public static final String GET_THROWABLE = "L" + THROWABLE + ";"; public static final String GET_TUPLE_TYPE_IMPL = "L" + TUPLE_TYPE_IMPL + ";"; public static final String GET_TYPE = "L" + TYPE + ";"; @@ -288,11 +289,11 @@ public class JvmSignatures { public static final String INIT_CHANNEL_DETAILS = "(L" + STRING_VALUE + ";ZZ)V"; public static final String INIT_RECEIVE_FIELD = "(L" + STRING_VALUE + ";L" + STRING_VALUE + ";)V"; public static final String INIT_CLI_SPEC = "(L" + OPTION + ";[L" + OPERAND + ";[L" + STRING_VALUE + ";)V"; - public static final String INIT_CONFIG = "([L" + STRING_VALUE + ";[L" + PATH + ";L" + STRING_VALUE + ";)V"; - public static final String INIT_CONFIGURABLES = "(L" + MODULE + ";L" + MAP + ";[L" + STRING_VALUE + ";[L" - + PATH + ";L" + STRING_VALUE + ";)V"; + public static final String INIT_CONFIG = + "(L" + MAP + ";" + "[L" + STRING_VALUE + ";[L" + PATH + ";L" + STRING_VALUE + ";)V"; + public static final String INIT_CONFIGURABLES = + "(L" + MODULE + ";L" + MAP + ";[L" + STRING_VALUE + ";[L" + PATH + ";L" + STRING_VALUE + ";)V"; public static final String INIT_TEST_ARGS = "([L" + STRING_VALUE + ";)V"; - public static final String INIT_DECIMAL = "(L" + BIG_DECIMAL + ";)V"; public static final String INIT_ERROR = "(L" + B_STRING_VALUE + ";)V"; public static final String INIT_ERROR_TYPE_IMPL = "(L" + STRING_VALUE + ";L" + MODULE + ";)V"; public static final String INIT_FIELD_IMPL = "(L" + TYPE + ";L" + STRING_VALUE + ";J)V"; @@ -308,6 +309,8 @@ public class JvmSignatures { public static final String INIT_LIST_INITIAL_EXPRESSION_ENTRY = "(L" + OBJECT + ";)V"; public static final String INIT_LIST_INITIAL_SPREAD_ENTRY = "(L" + B_ARRAY + ";)V"; public static final String INIT_RUNTIME_REGISTRY = "(L" + RUNTIME_REGISTRY_CLASS + ";)V"; + public static final String MODULE_INITIALIZER = "(L" + STRAND_CLASS + ";)L" + OBJECT + ";"; + public static final String MODULE_STOP = "(L" + SCHEDULER + ";L" + FUTURE_VALUE + ";)V"; public static final String INIT_MAPPING_INITIAL_SPREAD_FIELD_ENTRY = "(L" + B_MAP + ";)V"; public static final String INIT_MODULE = "(L" + STRING_VALUE + ";L" + STRING_VALUE + ";L" + STRING_VALUE + ";Z)V"; public static final String INIT_NON_BMP_STRING_VALUE = "(L" + STRING_VALUE + ";[I)V"; @@ -326,7 +329,6 @@ public class JvmSignatures { public static final String INIT_TABLE_TYPE_WITH_FIELD_NAME_LIST = "(L" + TYPE + ";[L" + STRING_VALUE + ";Z)V"; public static final String INIT_TABLE_VALUE_IMPL = "(L" + TYPE + ";L" + ARRAY_VALUE + ";L" + ARRAY_VALUE + ";)V"; - public static final String INIT_TUPLE = "(L" + TYPE + ";[L" + B_LIST_INITIAL_VALUE_ENTRY + ";)V"; public static final String INIT_TUPLE_TYPE_IMPL = "(L" + STRING_VALUE + ";L" + MODULE + ";IZZ)V"; public static final String INIT_TYPEDESC = "(L" + TYPEDESC_VALUE + ";)V"; public static final String INIT_UNION_TYPE_IMPL = "(L" + STRING_VALUE + ";L" + MODULE + ";IZJ)V"; @@ -343,7 +345,6 @@ public class JvmSignatures { public static final String IS_CONCURRENT = "(L" + FUNCTION_POINTER + ";)Z"; public static final String JSON_GET_ELEMENT = "(L" + OBJECT + ";L" + B_STRING_VALUE + ";)L" + OBJECT + ";"; public static final String JSON_SET_ELEMENT = "(L" + OBJECT + ";L" + STRING_VALUE + ";L" + OBJECT + ";)V"; - public static final String LAMBDA_MAIN = "([L" + OBJECT + ";)L" + OBJECT + ";"; public static final String LAMBDA_STOP_DYNAMIC = "([L" + OBJECT + ";)L" + OBJECT + ";"; public static final String LINKED_HASH_SET_OP = "(L" + LINKED_HASH_SET + ";)V"; public static final String LOAD_JOBJECT_TYPE = "L" + OBJECT + ";"; @@ -405,7 +406,6 @@ public class JvmSignatures { public static final String STACK_FRAMES = "L" + STACK + ";"; public static final String RECORD_GET = "(L" + STRING_VALUE + ";L" + OBJECT + ";)L" + OBJECT + ";"; public static final String RECORD_GET_KEYS = "()[L" + OBJECT + ";"; - public static final String RECORD_INIT_WRAPPER = "(L" + STRAND_CLASS + ";L" + MAP_VALUE + ";)V"; public static final String RECORD_PUT = "(L" + STRING_VALUE + ";L" + OBJECT + ";L" + OBJECT + ";)L" + OBJECT + ";"; public static final String RECORD_REMOVE = "(L" + STRING_VALUE + ";L" + OBJECT + ";)L" + OBJECT + ";"; public static final String RECORD_SET = "()L" + SET + ";"; @@ -473,8 +473,6 @@ public class JvmSignatures { "(L" + TYPE + ";[L" + MAP_VALUE + ";L" + MAP_VALUE + ";)V"; public static final String TYPE_PARAMETER = "(L" + TYPE + ";)V"; public static final String UPDATE_CHANNEL_DETAILS = "([L" + CHANNEL_DETAILS + ";)V"; - public static final String VALUE_CLASS_INIT = "(L" + STRAND_CLASS + ";L" + MAP_VALUE + ";)L" + OBJECT + ";"; - public static final String VALUE_OF_DECIMAL = "(D)L" + BIG_DECIMAL + ";"; public static final String VALUE_OF_JSTRING = "(L" + OBJECT + ";)L" + STRING_VALUE + ";"; public static final String WAIT_RESULT = STRAND_CLASS + "$WaitResult"; public static final String XML_ADD_CHILDREN = "(L" + XML_VALUE + ";)V"; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmTerminatorGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmTerminatorGen.java index 2a4dd39b27c1..27938d6c9f82 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmTerminatorGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmTerminatorGen.java @@ -28,15 +28,16 @@ import org.wso2.ballerinalang.compiler.bir.codegen.internal.AsyncDataCollector; import org.wso2.ballerinalang.compiler.bir.codegen.internal.BIRVarToJVMIndexMap; import org.wso2.ballerinalang.compiler.bir.codegen.internal.LabelGenerator; +import org.wso2.ballerinalang.compiler.bir.codegen.internal.LambdaFunction; import org.wso2.ballerinalang.compiler.bir.codegen.internal.ScheduleFunctionInfo; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.BIRFunctionWrapper; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JIConstructorCall; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JIMethodCLICall; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JIMethodCall; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JTerminator; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JType; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JavaMethodCall; +import org.wso2.ballerinalang.compiler.bir.codegen.model.BIRFunctionWrapper; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JIConstructorCall; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JIMethodCLICall; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JIMethodCall; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JTerminator; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JType; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JavaMethodCall; +import org.wso2.ballerinalang.compiler.bir.codegen.split.JvmConstantsGen; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; import org.wso2.ballerinalang.compiler.bir.model.BIROperand; import org.wso2.ballerinalang.compiler.bir.model.BIRTerminator; @@ -73,11 +74,9 @@ import static org.objectweb.asm.Opcodes.ATHROW; import static org.objectweb.asm.Opcodes.BIPUSH; import static org.objectweb.asm.Opcodes.CHECKCAST; -import static org.objectweb.asm.Opcodes.DCONST_0; import static org.objectweb.asm.Opcodes.DLOAD; import static org.objectweb.asm.Opcodes.DRETURN; import static org.objectweb.asm.Opcodes.DUP; -import static org.objectweb.asm.Opcodes.FCONST_0; import static org.objectweb.asm.Opcodes.GETFIELD; import static org.objectweb.asm.Opcodes.GETSTATIC; import static org.objectweb.asm.Opcodes.GOTO; @@ -96,7 +95,6 @@ import static org.objectweb.asm.Opcodes.IRETURN; import static org.objectweb.asm.Opcodes.ISTORE; import static org.objectweb.asm.Opcodes.L2I; -import static org.objectweb.asm.Opcodes.LCONST_0; import static org.objectweb.asm.Opcodes.LLOAD; import static org.objectweb.asm.Opcodes.LRETURN; import static org.objectweb.asm.Opcodes.NEW; @@ -109,11 +107,9 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.ARRAY_VALUE_IMPL; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.BAL_ENV_CLASS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.BAL_EXTENSION; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.BIG_DECIMAL; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.BLOCKED_ON_EXTERN_FIELD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.B_OBJECT; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CURRENT_MODULE_VAR_NAME; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.DECIMAL_VALUE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.DEFAULT_STRAND_DISPATCHER; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.ERROR_CODES; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.ERROR_HELPER; @@ -127,13 +123,13 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.INT_VALUE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.IS_BLOCKED_ON_EXTERN_FIELD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.JVM_INIT_METHOD; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.LAMBDA_PREFIX; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.LIST; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.LOCK_STORE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.LOCK_STORE_VAR_NAME; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.LOCK_VALUE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MAKE_CONCAT_WITH_CONSTANTS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MAP; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.MODULE_INITIALIZER; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_INIT_CLASS_NAME; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.OBJECT; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.PANIC_FIELD; @@ -186,7 +182,6 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.HANDLE_WORKER_ERROR; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_ANYDATA_ARRAY; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_BAL_ENV_WITH_FUNC_NAME; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_DECIMAL; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_RECEIVE_FIELD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INT_TO_STRING; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INT_VALUE_OF_METHOD; @@ -205,7 +200,6 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.SEND_DATA; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.SYNC_SEND_DATA; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.TRY_TAKE_DATA; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.VALUE_OF_DECIMAL; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.VOID_METHOD_DESC; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.WAIT_RESULT; import static org.wso2.ballerinalang.compiler.bir.codegen.interop.InteropMethodGen.genVarArg; @@ -217,25 +211,27 @@ */ public class JvmTerminatorGen { - private MethodVisitor mv; - private BIRVarToJVMIndexMap indexMap; - private LabelGenerator labelGen; - private JvmErrorGen errorGen; - private String currentPackageName; - private String moduleInitClass; - private JvmPackageGen jvmPackageGen; - private JvmInstructionGen jvmInstructionGen; - private PackageCache packageCache; - private SymbolTable symbolTable; - private Unifier unifier; - private JvmTypeGen jvmTypeGen; - private JvmCastGen jvmCastGen; - private AsyncDataCollector asyncDataCollector; + private final MethodVisitor mv; + private final BIRVarToJVMIndexMap indexMap; + private final LabelGenerator labelGen; + private final JvmErrorGen errorGen; + private final String currentPackageName; + private final String moduleInitClass; + private final JvmPackageGen jvmPackageGen; + private final JvmInstructionGen jvmInstructionGen; + private final PackageCache packageCache; + private final SymbolTable symbolTable; + private final Unifier unifier; + private final JvmTypeGen jvmTypeGen; + private final JvmCastGen jvmCastGen; + private final AsyncDataCollector asyncDataCollector; + private final String strandMetadataClass; public JvmTerminatorGen(MethodVisitor mv, BIRVarToJVMIndexMap indexMap, LabelGenerator labelGen, JvmErrorGen errorGen, PackageID packageID, JvmInstructionGen jvmInstructionGen, JvmPackageGen jvmPackageGen, JvmTypeGen jvmTypeGen, - JvmCastGen jvmCastGen, AsyncDataCollector asyncDataCollector) { + JvmCastGen jvmCastGen, JvmConstantsGen jvmConstantsGen, + AsyncDataCollector asyncDataCollector) { this.mv = mv; this.indexMap = indexMap; @@ -251,6 +247,7 @@ public JvmTerminatorGen(MethodVisitor mv, BIRVarToJVMIndexMap indexMap, LabelGen this.moduleInitClass = JvmCodeGenUtil.getModuleLevelClassName(packageID, MODULE_INIT_CLASS_NAME); this.unifier = new Unifier(); this.asyncDataCollector = asyncDataCollector; + this.strandMetadataClass = jvmConstantsGen.getStrandMetadataConstantsClass(); } private static void genYieldCheckForLock(MethodVisitor mv, LabelGenerator labelGen, String funcName, @@ -263,91 +260,6 @@ private static void genYieldCheckForLock(MethodVisitor mv, LabelGenerator labelG terminatorPos, fullyQualifiedFuncName, "WAITING FOR LOCK", yieldStatusVarIndex); } - private void loadDefaultValue(MethodVisitor mv, BType type) { - BType bType = JvmCodeGenUtil.getImpliedType(type); - if (TypeTags.isIntegerTypeTag(bType.tag)) { - mv.visitInsn(LCONST_0); - return; - } else if (TypeTags.isStringTypeTag(bType.tag) || TypeTags.isXMLTypeTag(bType.tag)) { - mv.visitInsn(ACONST_NULL); - return; - } - - switch (bType.tag) { - case TypeTags.FLOAT: - mv.visitInsn(DCONST_0); - break; - case TypeTags.BYTE: - case TypeTags.BOOLEAN: - mv.visitInsn(ICONST_0); - break; - case TypeTags.MAP: - case TypeTags.ARRAY: - case TypeTags.ERROR: - case TypeTags.NIL: - case TypeTags.NEVER: - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.OBJECT: - case TypeTags.UNION: - case TypeTags.RECORD: - case TypeTags.TUPLE: - case TypeTags.FUTURE: - case TypeTags.JSON: - case TypeTags.INVOKABLE: - case TypeTags.FINITE: - case TypeTags.HANDLE: - case TypeTags.TYPEDESC: - case TypeTags.READONLY: - case TypeTags.STREAM: - mv.visitInsn(ACONST_NULL); - break; - case TypeTags.DECIMAL: - mv.visitTypeInsn(NEW, DECIMAL_VALUE); - mv.visitInsn(DUP); - mv.visitInsn(DCONST_0); - mv.visitMethodInsn(INVOKESTATIC, BIG_DECIMAL, VALUE_OF_METHOD, VALUE_OF_DECIMAL, - false); - mv.visitMethodInsn(INVOKESPECIAL, DECIMAL_VALUE, JVM_INIT_METHOD, INIT_DECIMAL, - false); - break; - case JTypeTags.JTYPE: - loadDefaultJValue(mv, (JType) bType); - break; - default: - throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + - bType); - } - } - - private void loadDefaultJValue(MethodVisitor mv, JType jType) { - switch (jType.jTag) { - case JTypeTags.JBYTE: - case JTypeTags.JBOOLEAN: - case JTypeTags.JINT: - case JTypeTags.JSHORT: - case JTypeTags.JCHAR: - mv.visitInsn(ICONST_0); - break; - case JTypeTags.JLONG: - mv.visitInsn(LCONST_0); - break; - case JTypeTags.JFLOAT: - mv.visitInsn(FCONST_0); - break; - case JTypeTags.JDOUBLE: - mv.visitInsn(DCONST_0); - break; - case JTypeTags.JARRAY: - case JTypeTags.JREF: - mv.visitInsn(ACONST_NULL); - break; - default: - throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + - jType); - } - } - public void genTerminator(BIRTerminator terminator, String moduleClassName, BIRNode.BIRFunction func, String funcName, int localVarOffset, int stateVarIndex, int returnVarRefIndex, BType attachedType, int yieldLocationVarIndex, int yieldStatusVarIndex, @@ -355,63 +267,80 @@ public void genTerminator(BIRTerminator terminator, String moduleClassName, BIRN BIRNode.BIRBasicBlock currentBB, Label loopLabel) { switch (terminator.kind) { - case LOCK: + case LOCK -> { this.genLockTerm((BIRTerminator.Lock) terminator, funcName, localVarOffset, yieldLocationVarIndex, terminator.pos, fullyQualifiedFuncName, yieldStatusVarIndex); return; - case UNLOCK: + } + case UNLOCK -> { this.genUnlockTerm((BIRTerminator.Unlock) terminator, funcName); return; - case GOTO: + } + case GOTO -> { this.genGoToTerm((BIRTerminator.GOTO) terminator, funcName, currentBB, stateVarIndex, loopVarIndex, loopLabel); return; - case CALL: + } + case CALL -> { this.genCallTerm((BIRTerminator.Call) terminator, localVarOffset); return; - case ASYNC_CALL: + } + case ASYNC_CALL -> { this.genAsyncCallTerm((BIRTerminator.AsyncCall) terminator, localVarOffset, - moduleClassName, attachedType, funcName); + moduleClassName, attachedType, funcName); return; - case BRANCH: + } + case BRANCH -> { this.genBranchTerm((BIRTerminator.Branch) terminator, funcName); return; - case RETURN: + } + case RETURN -> { this.genReturnTerm(returnVarRefIndex, func, invocationVarIndex, localVarOffset); return; - case PANIC: + } + case PANIC -> { this.errorGen.genPanic((BIRTerminator.Panic) terminator); return; - case WAIT: + } + case WAIT -> { this.generateWaitIns((BIRTerminator.Wait) terminator, localVarOffset); return; - case WAIT_ALL: + } + case WAIT_ALL -> { this.genWaitAllIns((BIRTerminator.WaitAll) terminator, localVarOffset); return; - case FP_CALL: + } + case FP_CALL -> { this.genFPCallIns((BIRTerminator.FPCall) terminator, moduleClassName, attachedType, - funcName, localVarOffset, invocationVarIndex); + funcName, localVarOffset, invocationVarIndex); return; - case WK_SEND: + } + case WK_SEND -> { this.genWorkerSendIns((BIRTerminator.WorkerSend) terminator, localVarOffset, invocationVarIndex); return; - case WK_RECEIVE: + } + case WK_RECEIVE -> { this.genWorkerReceiveIns((BIRTerminator.WorkerReceive) terminator, localVarOffset, invocationVarIndex); return; - case WK_ALT_RECEIVE: + } + case WK_ALT_RECEIVE -> { this.genWorkerAlternateReceiveIns((BIRTerminator.WorkerAlternateReceive) terminator, localVarOffset, invocationVarIndex); return; - case WK_MULTIPLE_RECEIVE: + } + case WK_MULTIPLE_RECEIVE -> { this.genWorkerMultipleReceiveIns((BIRTerminator.WorkerMultipleReceive) terminator, localVarOffset, invocationVarIndex); return; - case FLUSH: + } + case FLUSH -> { this.genFlushIns((BIRTerminator.Flush) terminator, localVarOffset, invocationVarIndex); return; - case PLATFORM: + } + case PLATFORM -> { this.genPlatformIns((JTerminator) terminator, attachedType, localVarOffset, func); return; + } } throw new BLangCompilerException("JVM generation is not supported for terminator instruction " + terminator); @@ -524,21 +453,12 @@ private void genCallTerm(BIRTerminator.Call callIns, int localVarOffset) { private void genPlatformIns(JTerminator terminator, BType attachedType, int localVarOffset, BIRNode.BIRFunction func) { switch (terminator.jTermKind) { - case J_METHOD_CALL: - this.genJCallTerm((JavaMethodCall) terminator, attachedType, localVarOffset); - return; - case JI_METHOD_CALL: - this.genJICallTerm((JIMethodCall) terminator, localVarOffset, func); - return; - case JI_CONSTRUCTOR_CALL: - this.genJIConstructorTerm((JIConstructorCall) terminator, localVarOffset); - return; - case JI_METHOD_CLI_CALL: - this.genJICLICallTerm((JIMethodCLICall) terminator, localVarOffset); - return; - default: - throw new BLangCompilerException("JVM generation is not supported for terminator instruction " + - terminator); + case J_METHOD_CALL -> this.genJCallTerm((JavaMethodCall) terminator, attachedType, localVarOffset); + case JI_METHOD_CALL -> this.genJICallTerm((JIMethodCall) terminator, localVarOffset, func); + case JI_CONSTRUCTOR_CALL -> this.genJIConstructorTerm((JIConstructorCall) terminator, localVarOffset); + case JI_METHOD_CLI_CALL -> this.genJICLICallTerm((JIMethodCLICall) terminator, localVarOffset); + default -> throw new BLangCompilerException("JVM generation is not supported for terminator instruction " + + terminator); } } @@ -574,7 +494,7 @@ private void genJICLICallTerm(JIMethodCLICall terminator, int localVarOffset) { } private void genJCallTerm(JavaMethodCall callIns, BType attachedType, int localVarOffset) { - // Load function parameters of the target Java method to the stack.. + // Load function parameters of the target Java method to the stack. Label blockedOnExternLabel = new Label(); Label notBlockedOnExternLabel = new Label(); @@ -595,7 +515,7 @@ private void genJCallTerm(JavaMethodCall callIns, BType attachedType, int localV if (attachedType == null) { this.mv.visitVarInsn(ALOAD, localVarOffset); } else { - // Below codes are not needed (as normal external funcs doesn't support attached invocations) + // Below codes are not needed (as normal external functions doesn't support attached invocations) // check whether function params already include the self this.mv.visitVarInsn(ALOAD, localVarOffset); BIRNode.BIRVariableDcl selfArg = callIns.args.get(0).variableDcl; @@ -622,7 +542,7 @@ private void genJCallTerm(JavaMethodCall callIns, BType attachedType, int localV } private void genJICallTerm(JIMethodCall callIns, int localVarOffset, BIRNode.BIRFunction func) { - // Load function parameters of the target Java method to the stack.. + // Load function parameters of the target Java method to the stack. Label blockedOnExternLabel = new Label(); Label notBlockedOnExternLabel = new Label(); @@ -743,7 +663,7 @@ private void genJICallTerm(JIMethodCall callIns, int localVarOffset, BIRNode.BIR } private void genJIConstructorTerm(JIConstructorCall callIns, int localVarOffset) { - // Load function parameters of the target Java method to the stack.. + // Load function parameters of the target Java method to the stack. Label blockedOnExternLabel = new Label(); Label notBlockedOnExternLabel = new Label(); @@ -876,13 +796,21 @@ private void genStaticCall(BIRTerminator.Call callIns, PackageID packageID, int String methodDesc; String jvmClass; if (functionWrapper != null) { - jvmClass = functionWrapper.fullQualifiedClassName; - methodDesc = functionWrapper.jvmMethodDescription; + jvmClass = functionWrapper.fullQualifiedClassName(); + methodDesc = functionWrapper.jvmMethodDescription(); } else { BPackageSymbol symbol = packageCache.getSymbol( packageID.orgName.getValue() + "/" + packageID.name.getValue()); Name decodedMethodName = new Name(Utils.decodeIdentifier(methodName)); BInvokableSymbol funcSymbol = (BInvokableSymbol) symbol.scope.lookup(decodedMethodName).symbol; + if (funcSymbol == null && JvmCodeGenUtil.isModuleInitializerMethod(decodedMethodName.value)) { + // moduleInit() and moduleStart() functions are not present in the BIR cache because they are generated + // in CodeGen phase. Therefore, they are not found inside the packageSymbol scope. + jvmClass = JvmCodeGenUtil.getModuleLevelClassName(packageID, + JvmCodeGenUtil.cleanupPathSeparators(MODULE_INIT_CLASS_NAME)); + this.mv.visitMethodInsn(INVOKESTATIC, jvmClass, encodedMethodName, MODULE_INITIALIZER, false); + return; + } BInvokableType type = (BInvokableType) funcSymbol.type; ArrayList params = new ArrayList<>(type.paramTypes); if (type.restType != null) { @@ -890,7 +818,6 @@ private void genStaticCall(BIRTerminator.Call callIns, PackageID packageID, int } String balFileName = funcSymbol.source; - if (balFileName == null || !balFileName.endsWith(BAL_EXTENSION)) { balFileName = MODULE_INIT_CLASS_NAME; } @@ -914,7 +841,7 @@ private void genVirtualCall(BIRTerminator.Call callIns, int localVarOffset) { this.mv.visitVarInsn(ALOAD, localVarOffset); // load the function name as the second argument - this.mv.visitLdcInsn(JvmCodeGenUtil.rewriteVirtualCallTypeName(callIns.name.value)); + this.mv.visitLdcInsn(JvmCodeGenUtil.rewriteVirtualCallTypeName(callIns.name.value, selfArg.type)); // create an Object[] for the rest params int argsCount = callIns.args.size() - 1; this.mv.visitLdcInsn((long) (argsCount)); @@ -932,15 +859,14 @@ private void genVirtualCall(BIRTerminator.Call callIns, int localVarOffset) { BIROperand arg = callIns.args.get(i + 1); this.loadVar(arg.variableDcl); - // Add the to the rest params array + // Add to the rest params array jvmCastGen.addBoxInsn(this.mv, arg.variableDcl.type); this.mv.visitInsn(AASTORE); i += 1; } // call method - String methodDesc = BOBJECT_CALL; - this.mv.visitMethodInsn(INVOKEINTERFACE, B_OBJECT, "call", methodDesc, true); + this.mv.visitMethodInsn(INVOKEINTERFACE, B_OBJECT, "call", BOBJECT_CALL, true); BType returnType = callIns.lhsOp.variableDcl.type; jvmCastGen.addUnboxInsn(this.mv, returnType); @@ -948,12 +874,6 @@ private void genVirtualCall(BIRTerminator.Call callIns, int localVarOffset) { private void genAsyncCallTerm(BIRTerminator.AsyncCall callIns, int localVarOffset, String moduleClassName, BType attachedType, String parentFunction) { - - PackageID calleePkgId = callIns.calleePkg; - - String orgName = calleePkgId.orgName.value; - String moduleName = calleePkgId.name.value; - // Check if already locked before submitting to scheduler. String lockStore = "L" + LOCK_STORE + ";"; String initClassName = jvmPackageGen.lookupGlobalVarClassName(this.currentPackageName, LOCK_STORE_VAR_NAME); @@ -979,22 +899,19 @@ private void genAsyncCallTerm(BIRTerminator.AsyncCall callIns, int localVarOffse this.mv.visitInsn(L2I); this.loadVar(arg.variableDcl); - // Add the to the rest params array + // Add to the rest params array jvmCastGen.addBoxInsn(this.mv, arg.variableDcl.type); this.mv.visitInsn(AASTORE); paramIndex += 1; } - String funcName = Utils.encodeFunctionIdentifier(callIns.name.value); - String lambdaName = "$" + funcName + LAMBDA_PREFIX + "_" + asyncDataCollector.getLambdaIndex() + "$"; - JvmCodeGenUtil.createFunctionPointer(this.mv, asyncDataCollector.getEnclosingClass(), lambdaName); - asyncDataCollector.add(lambdaName, callIns); - asyncDataCollector.incrementLambdaIndex(); + LambdaFunction lambdaFunction = asyncDataCollector.addAndGetLambda(callIns.name.value, callIns, true); + JvmCodeGenUtil.createFunctionPointer(this.mv, lambdaFunction.enclosingClass, lambdaFunction.lambdaName); boolean concurrent = false; String strandName = null; // check for concurrent annotation - if (callIns.annotAttachments.size() > 0) { + if (!callIns.annotAttachments.isEmpty()) { for (BIRNode.BIRAnnotationAttachment annotationAttachment : callIns.annotAttachments) { if (annotationAttachment == null || !STRAND.equals(annotationAttachment.annotTagRef.value) || @@ -1003,21 +920,21 @@ private void genAsyncCallTerm(BIRTerminator.AsyncCall callIns, int localVarOffse } Object strandAnnot = ((BIRNode.BIRConstAnnotationAttachment) annotationAttachment).annotValue.value; - if (strandAnnot instanceof Map) { - Map recordValue = (Map) strandAnnot; + if (strandAnnot instanceof Map recordValue) { if (recordValue.containsKey(STRAND_THREAD)) { - if (STRAND_VALUE_ANY.equals(recordValue.get(STRAND_THREAD).value)) { + if (STRAND_VALUE_ANY.equals(((BIRNode.ConstValue) recordValue.get(STRAND_THREAD)).value)) { concurrent = true; } } if (recordValue.containsKey(STRAND_NAME)) { - strandName = recordValue.get(STRAND_NAME).value.toString(); + strandName = ((BIRNode.ConstValue) recordValue.get(STRAND_NAME)).value.toString(); } if (recordValue.containsKey(STRAND_POLICY_NAME)) { - if (!DEFAULT_STRAND_DISPATCHER.equals(recordValue.get(STRAND_POLICY_NAME).value)) { + if (!DEFAULT_STRAND_DISPATCHER.equals( + ((BIRNode.ConstValue) recordValue.get(STRAND_POLICY_NAME)).value)) { throw new BLangCompilerException("Unsupported policy. Only 'DEFAULT' policy is " + "supported by jBallerina runtime."); } @@ -1039,7 +956,7 @@ private void genAsyncCallTerm(BIRTerminator.AsyncCall callIns, int localVarOffse this.mv.visitLdcInsn(workerName); } - this.submitToScheduler(callIns.lhsOp, moduleClassName, attachedType, parentFunction, concurrent); + this.submitToScheduler(callIns.lhsOp, attachedType, parentFunction, concurrent); } private void generateWaitIns(BIRTerminator.Wait waitInst, int localVarOffset) { @@ -1186,7 +1103,7 @@ private void genFPCallIns(BIRTerminator.FPCall fpCall, String moduleClassName, B } this.mv.visitMethodInsn(INVOKESTATIC, ANNOTATION_UTILS, "getStrandName", ANNOTATION_GET_STRAND, false); - this.submitToScheduler(fpCall.lhsOp, moduleClassName, attachedType, funcName, true); + this.submitToScheduler(fpCall.lhsOp, attachedType, funcName, true); Label afterSubmit = new Label(); this.mv.visitJumpInsn(GOTO, afterSubmit); this.mv.visitLabel(notConcurrent); @@ -1201,7 +1118,7 @@ private void genFPCallIns(BIRTerminator.FPCall fpCall, String moduleClassName, B } this.mv.visitMethodInsn(INVOKESTATIC, ANNOTATION_UTILS, "getStrandName", ANNOTATION_GET_STRAND, false); - this.submitToScheduler(fpCall.lhsOp, moduleClassName, attachedType, funcName, false); + this.submitToScheduler(fpCall.lhsOp, attachedType, funcName, false); this.mv.visitLabel(afterSubmit); } else { this.mv.visitMethodInsn(INVOKEINTERFACE, FUNCTION, "apply", @@ -1369,22 +1286,16 @@ private void genFlushIns(BIRTerminator.Flush ins, int localVarOffset, int invoca this.storeToVar(ins.lhsOp.variableDcl); } - private void submitToScheduler(BIROperand lhsOp, String moduleClassName, BType attachedType, - String parentFunction, boolean concurrent) { + private void submitToScheduler(BIROperand lhsOp, BType attachedType, String parentFunction, boolean concurrent) { String metaDataVarName; - ScheduleFunctionInfo strandMetaData; if (attachedType != null) { - metaDataVarName = getStrandMetadataVarName(attachedType.tsymbol.name.value, - parentFunction); - strandMetaData = new ScheduleFunctionInfo(attachedType.tsymbol.name.value, parentFunction); + metaDataVarName = setAndGetStrandMetadataVarName(attachedType.tsymbol.name.value, parentFunction, + asyncDataCollector); } else { - metaDataVarName = JvmCodeGenUtil.getStrandMetadataVarName(parentFunction); - strandMetaData = new ScheduleFunctionInfo(parentFunction); - + metaDataVarName = JvmCodeGenUtil.setAndGetStrandMetadataVarName(parentFunction, asyncDataCollector); } - asyncDataCollector.getStrandMetadata().putIfAbsent(metaDataVarName, strandMetaData); - this.mv.visitFieldInsn(GETSTATIC, moduleClassName, metaDataVarName, GET_STRAND_METADATA); + this.mv.visitFieldInsn(GETSTATIC, this.strandMetadataClass, metaDataVarName, GET_STRAND_METADATA); if (concurrent) { mv.visitMethodInsn(INVOKEVIRTUAL, SCHEDULER, SCHEDULE_FUNCTION_METHOD, SCHEDULE_FUNCTION, false); @@ -1400,9 +1311,12 @@ private void submitToScheduler(BIROperand lhsOp, String moduleClassName, BType a } } - static String getStrandMetadataVarName(String typeName, String parentFunction) { - return STRAND_METADATA_VAR_PREFIX + typeName + "$" + parentFunction + - "$"; + private String setAndGetStrandMetadataVarName(String typeName, String parentFunction, + AsyncDataCollector asyncDataCollector) { + String metaDataVarName = STRAND_METADATA_VAR_PREFIX + typeName + "$" + parentFunction + "$"; + asyncDataCollector.getStrandMetadata().putIfAbsent(metaDataVarName, + new ScheduleFunctionInfo(typeName, parentFunction)); + return metaDataVarName; } private void loadFpReturnType(BIROperand lhsOp) { @@ -1430,16 +1344,17 @@ private void storeToVar(BIRNode.BIRVariableDcl varDcl) { private void genResourcePathArgs(List pathArgs) { int pathVarArrayIndex = this.indexMap.addIfNotExists("$pathVarArray", symbolTable.anyType); int bundledArrayIndex = this.indexMap.addIfNotExists("$pathArrayArgs", symbolTable.anyType); - genBundledArgs(pathArgs, pathVarArrayIndex, bundledArrayIndex, TYPE_ANYDATA_ARRAY); + genBundledArgs(pathArgs, pathVarArrayIndex, bundledArrayIndex, TYPE_ANYDATA_ARRAY, true); } private void genBundledFunctionArgs(List args) { int functionArgArrayIndex = this.indexMap.addIfNotExists("$functionArgArray", symbolTable.anyType); int bundledArrayIndex = this.indexMap.addIfNotExists("$functionArrayArgs", symbolTable.anyType); - genBundledArgs(args, functionArgArrayIndex, bundledArrayIndex, TYPE_ANY_ARRAY); + genBundledArgs(args, functionArgArrayIndex, bundledArrayIndex, TYPE_ANY_ARRAY, false); } - private void genBundledArgs(List args, int argsArrayIndex, int bundledArrayIndex, String fieldName) { + private void genBundledArgs(List args, int argsArrayIndex, int bundledArrayIndex, String fieldName, + boolean isFromPathArgs) { mv.visitLdcInsn((long) args.size()); mv.visitInsn(L2I); mv.visitTypeInsn(ANEWARRAY, OBJECT); @@ -1451,7 +1366,13 @@ private void genBundledArgs(List args, int argsArrayIndex, int bundl mv.visitLdcInsn((long) i); mv.visitInsn(L2I); this.loadVar(arg.variableDcl); - jvmCastGen.generateCheckCastToAnyData(mv, arg.variableDcl.type); + if (isFromPathArgs) { + // Add CheckCast instruction for path args. + jvmCastGen.generateCheckCastToAnyData(mv, arg.variableDcl.type); + } else { + // Add Box instruction if the type is a value type. + jvmCastGen.addBoxInsn(mv, arg.variableDcl.type); + } mv.visitInsn(AASTORE); i++; } @@ -1505,51 +1426,34 @@ private void generateReturnTermFromType(int returnVarRefIndex, BType bType, BIRN } switch (bType.tag) { - case TypeTags.NIL: - case TypeTags.NEVER: - case TypeTags.MAP: - case TypeTags.ARRAY: - case TypeTags.ANY: - case TypeTags.STREAM: - case TypeTags.TABLE: - case TypeTags.ANYDATA: - case TypeTags.OBJECT: - case TypeTags.DECIMAL: - case TypeTags.RECORD: - case TypeTags.TUPLE: - case TypeTags.JSON: - case TypeTags.FUTURE: - case TypeTags.INVOKABLE: - case TypeTags.HANDLE: - case TypeTags.FINITE: - case TypeTags.TYPEDESC: - case TypeTags.READONLY: + case TypeTags.NIL, TypeTags.NEVER, TypeTags.MAP, TypeTags.ARRAY, TypeTags.ANY, TypeTags.STREAM, + TypeTags.TABLE, TypeTags.ANYDATA, TypeTags.OBJECT, TypeTags.DECIMAL, TypeTags.RECORD, + TypeTags.TUPLE, TypeTags.JSON, TypeTags.FUTURE, TypeTags.INVOKABLE, TypeTags.HANDLE, + TypeTags.FINITE, TypeTags.TYPEDESC, TypeTags.READONLY -> { this.mv.visitVarInsn(ALOAD, returnVarRefIndex); this.mv.visitInsn(ARETURN); - break; - case TypeTags.BYTE: - case TypeTags.BOOLEAN: + } + case TypeTags.BYTE, TypeTags.BOOLEAN -> { this.mv.visitVarInsn(ILOAD, returnVarRefIndex); this.mv.visitInsn(IRETURN); - break; - case TypeTags.FLOAT: + } + case TypeTags.FLOAT -> { this.mv.visitVarInsn(DLOAD, returnVarRefIndex); this.mv.visitInsn(DRETURN); - break; - case TypeTags.UNION: + } + case TypeTags.UNION -> { this.handleErrorRetInUnion(returnVarRefIndex, Arrays.asList(func.workerChannels), (BUnionType) bType, invocationVarIndex, localVarOffset); this.mv.visitVarInsn(ALOAD, returnVarRefIndex); this.mv.visitInsn(ARETURN); - break; - case TypeTags.ERROR: + } + case TypeTags.ERROR -> { this.notifyChannels(Arrays.asList(func.workerChannels), returnVarRefIndex, invocationVarIndex); this.mv.visitVarInsn(ALOAD, returnVarRefIndex); this.mv.visitInsn(ARETURN); - break; - default: - throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + - func.type.retType); + } + default -> throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + + func.type.retType); } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmTypeGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmTypeGen.java index d18cc4b54aaa..e6d31db01347 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmTypeGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmTypeGen.java @@ -18,7 +18,6 @@ package org.wso2.ballerinalang.compiler.bir.codegen; import io.ballerina.identifier.Utils; -import org.apache.commons.lang3.StringEscapeUtils; import org.ballerinalang.compiler.BLangCompilerException; import org.ballerinalang.model.elements.PackageID; import org.ballerinalang.model.symbols.SymbolKind; @@ -354,149 +353,126 @@ public void loadType(MethodVisitor mv, BType bType) { typeFieldName = "TYPE_NULL"; } else { switch (bType.tag) { - case TypeTags.NEVER: - typeFieldName = "TYPE_NEVER"; - break; - case TypeTags.INT: - typeFieldName = "TYPE_INT"; - break; - case TypeTags.SIGNED32_INT: - typeFieldName = "TYPE_INT_SIGNED_32"; - break; - case TypeTags.SIGNED16_INT: - typeFieldName = "TYPE_INT_SIGNED_16"; - break; - case TypeTags.SIGNED8_INT: - typeFieldName = "TYPE_INT_SIGNED_8"; - break; - case TypeTags.UNSIGNED32_INT: - typeFieldName = "TYPE_INT_UNSIGNED_32"; - break; - case TypeTags.UNSIGNED16_INT: - typeFieldName = "TYPE_INT_UNSIGNED_16"; - break; - case TypeTags.UNSIGNED8_INT: - typeFieldName = "TYPE_INT_UNSIGNED_8"; - break; - case TypeTags.FLOAT: - typeFieldName = "TYPE_FLOAT"; - break; - case TypeTags.STRING: - typeFieldName = "TYPE_STRING"; - break; - case TypeTags.CHAR_STRING: - typeFieldName = "TYPE_STRING_CHAR"; - break; - case TypeTags.DECIMAL: - typeFieldName = "TYPE_DECIMAL"; - break; - case TypeTags.BOOLEAN: - typeFieldName = "TYPE_BOOLEAN"; - break; - case TypeTags.BYTE: - typeFieldName = "TYPE_BYTE"; - break; - case TypeTags.ANY: - typeFieldName = Symbols.isFlagOn(bType.flags, Flags.READONLY) ? "TYPE_READONLY_ANY" : "TYPE_ANY"; - break; - case TypeTags.ANYDATA: - case TypeTags.REGEXP: - typeFieldName = Symbols.isFlagOn(bType.flags, Flags.READONLY) ? "TYPE_READONLY_ANYDATA" : - "TYPE_ANYDATA"; - break; - case TypeTags.JSON: - typeFieldName = Symbols.isFlagOn(bType.flags, Flags.READONLY) ? "TYPE_READONLY_JSON" : "TYPE_JSON"; - break; - case TypeTags.XML: + case TypeTags.NEVER -> typeFieldName = "TYPE_NEVER"; + case TypeTags.INT -> typeFieldName = "TYPE_INT"; + case TypeTags.SIGNED32_INT -> typeFieldName = "TYPE_INT_SIGNED_32"; + case TypeTags.SIGNED16_INT -> typeFieldName = "TYPE_INT_SIGNED_16"; + case TypeTags.SIGNED8_INT -> typeFieldName = "TYPE_INT_SIGNED_8"; + case TypeTags.UNSIGNED32_INT -> typeFieldName = "TYPE_INT_UNSIGNED_32"; + case TypeTags.UNSIGNED16_INT -> typeFieldName = "TYPE_INT_UNSIGNED_16"; + case TypeTags.UNSIGNED8_INT -> typeFieldName = "TYPE_INT_UNSIGNED_8"; + case TypeTags.FLOAT -> typeFieldName = "TYPE_FLOAT"; + case TypeTags.STRING -> typeFieldName = "TYPE_STRING"; + case TypeTags.CHAR_STRING -> typeFieldName = "TYPE_STRING_CHAR"; + case TypeTags.DECIMAL -> typeFieldName = "TYPE_DECIMAL"; + case TypeTags.BOOLEAN -> typeFieldName = "TYPE_BOOLEAN"; + case TypeTags.BYTE -> typeFieldName = "TYPE_BYTE"; + case TypeTags.ANY -> + typeFieldName = Symbols.isFlagOn(bType.flags, Flags.READONLY) ? "TYPE_READONLY_ANY" : + "TYPE_ANY"; + case TypeTags.ANYDATA, TypeTags.REGEXP -> + typeFieldName = Symbols.isFlagOn(bType.flags, Flags.READONLY) ? "TYPE_READONLY_ANYDATA" : + "TYPE_ANYDATA"; + case TypeTags.JSON -> + typeFieldName = Symbols.isFlagOn(bType.flags, Flags.READONLY) ? "TYPE_READONLY_JSON" : + "TYPE_JSON"; + case TypeTags.XML -> { loadXmlType(mv, (BXMLType) bType); return; - case TypeTags.XML_ELEMENT: - typeFieldName = Symbols.isFlagOn(bType.flags, Flags.READONLY) ? "TYPE_READONLY_ELEMENT" : - "TYPE_ELEMENT"; - break; - case TypeTags.XML_PI: - typeFieldName = Symbols.isFlagOn(bType.flags, Flags.READONLY) ? - "TYPE_READONLY_PROCESSING_INSTRUCTION" : "TYPE_PROCESSING_INSTRUCTION"; - break; - case TypeTags.XML_COMMENT: - typeFieldName = Symbols.isFlagOn(bType.flags, Flags.READONLY) ? "TYPE_READONLY_COMMENT" : - "TYPE_COMMENT"; - break; - case TypeTags.XML_TEXT: - typeFieldName = "TYPE_TEXT"; - break; - case TypeTags.TYPEDESC: + } + case TypeTags.XML_ELEMENT -> + typeFieldName = Symbols.isFlagOn(bType.flags, Flags.READONLY) ? "TYPE_READONLY_ELEMENT" : + "TYPE_ELEMENT"; + case TypeTags.XML_PI -> typeFieldName = Symbols.isFlagOn(bType.flags, Flags.READONLY) ? + "TYPE_READONLY_PROCESSING_INSTRUCTION" : "TYPE_PROCESSING_INSTRUCTION"; + case TypeTags.XML_COMMENT -> + typeFieldName = Symbols.isFlagOn(bType.flags, Flags.READONLY) ? "TYPE_READONLY_COMMENT" : + "TYPE_COMMENT"; + case TypeTags.XML_TEXT -> typeFieldName = "TYPE_TEXT"; + case TypeTags.TYPEDESC -> { loadTypedescType(mv, (BTypedescType) bType); return; - case TypeTags.OBJECT: - case TypeTags.RECORD: + } + case TypeTags.OBJECT, TypeTags.RECORD -> { loadUserDefinedType(mv, bType); return; - case TypeTags.HANDLE: - typeFieldName = "TYPE_HANDLE"; - break; - case TypeTags.ARRAY: + } + case TypeTags.HANDLE -> typeFieldName = "TYPE_HANDLE"; + case TypeTags.ARRAY -> { jvmConstantsGen.generateGetBArrayType(mv, jvmConstantsGen.getTypeConstantsVar(bType, symbolTable)); return; - case TypeTags.MAP: + } + case TypeTags.MAP -> { loadMapType(mv, (BMapType) bType); return; - case TypeTags.STREAM: + } + case TypeTags.STREAM -> { loadStreamType(mv, (BStreamType) bType); return; - case TypeTags.TABLE: + } + case TypeTags.TABLE -> { loadTableType(mv, (BTableType) bType); return; - case TypeTags.ERROR: + } + case TypeTags.ERROR -> { loadErrorType(mv, (BErrorType) bType); return; - case TypeTags.UNION: + } + case TypeTags.UNION -> { BUnionType unionType = (BUnionType) bType; if (unionType.isCyclic) { loadUserDefinedType(mv, bType); } else { jvmConstantsGen.generateGetBUnionType(mv, - jvmConstantsGen.getTypeConstantsVar(bType, symbolTable)); + jvmConstantsGen.getTypeConstantsVar(bType, symbolTable)); } return; - case TypeTags.INTERSECTION: + } + case TypeTags.INTERSECTION -> { loadIntersectionType(mv, (BIntersectionType) bType); return; - case TypeTags.INVOKABLE: + } + case TypeTags.INVOKABLE -> { loadInvokableType(mv, (BInvokableType) bType); return; - case TypeTags.NONE: + } + case TypeTags.NONE -> { mv.visitInsn(ACONST_NULL); return; - case TypeTags.TUPLE: + } + case TypeTags.TUPLE -> { BTupleType tupleType = (BTupleType) bType; if (tupleType.isCyclic) { loadUserDefinedType(mv, bType); } else { jvmConstantsGen.generateGetBTupleType(mv, jvmConstantsGen.getTypeConstantsVar(tupleType, - symbolTable)); + symbolTable)); } return; - case TypeTags.FINITE: + } + case TypeTags.FINITE -> { loadFiniteType(mv, (BFiniteType) bType); return; - case TypeTags.FUTURE: + } + case TypeTags.FUTURE -> { loadFutureType(mv, (BFutureType) bType); return; - case TypeTags.READONLY: - typeFieldName = "TYPE_READONLY"; - break; - case TypeTags.PARAMETERIZED_TYPE: + } + case TypeTags.READONLY -> typeFieldName = "TYPE_READONLY"; + case TypeTags.PARAMETERIZED_TYPE -> { loadParameterizedType(mv, (BParameterizedType) bType); return; - case TypeTags.TYPEREFDESC: + } + case TypeTags.TYPEREFDESC -> { String typeOwner = JvmCodeGenUtil.getModuleLevelClassName(bType.tsymbol.pkgID, JvmConstants.TYPEREF_TYPE_CONSTANT_CLASS_NAME); mv.visitFieldInsn(GETSTATIC, typeOwner, JvmCodeGenUtil.getRefTypeConstantName((BTypeReferenceType) bType), GET_TYPE_REF_TYPE_IMPL); return; - default: + } + default -> { return; + } } } @@ -508,53 +484,28 @@ private String loadTypeClass(BType bType) { if (bType == null || bType.tag == TypeTags.NIL) { return LOAD_NULL_TYPE; } else { - switch (bType.tag) { - case TypeTags.NEVER: - return LOAD_NEVER_TYPE; - case TypeTags.INT: - case TypeTags.UNSIGNED8_INT: - case TypeTags.UNSIGNED16_INT: - case TypeTags.UNSIGNED32_INT: - case TypeTags.SIGNED8_INT: - case TypeTags.SIGNED16_INT: - case TypeTags.SIGNED32_INT: - return LOAD_INTEGER_TYPE; - case TypeTags.FLOAT: - return LOAD_FLOAT_TYPE; - case TypeTags.STRING: - case TypeTags.CHAR_STRING: - return LOAD_STRING_TYPE; - case TypeTags.DECIMAL: - return LOAD_DECIMAL_TYPE; - case TypeTags.BOOLEAN: - return LOAD_BOOLEAN_TYPE; - case TypeTags.BYTE: - return LOAD_BYTE_TYPE; - case TypeTags.ANY: - return LOAD_ANY_TYPE; - case TypeTags.ANYDATA: - case TypeTags.REGEXP: - return LOAD_ANYDATA_TYPE; - case TypeTags.JSON: - return LOAD_JSON_TYPE; - case TypeTags.XML: - case TypeTags.XML_TEXT: - return LOAD_XML_TYPE; - case TypeTags.XML_ELEMENT: - case TypeTags.XML_PI: - case TypeTags.XML_COMMENT: - return Symbols.isFlagOn(bType.flags, Flags.READONLY) ? LOAD_TYPE : LOAD_XML_TYPE; - case TypeTags.OBJECT: - return Symbols.isService(bType.tsymbol) ? LOAD_SERVICE_TYPE : LOAD_OBJECT_TYPE; - case TypeTags.HANDLE: - return LOAD_HANDLE_TYPE; - case TypeTags.READONLY: - return LOAD_READONLY_TYPE; - case TypeTags.UNION: - return LOAD_UNION_TYPE; - default: - return LOAD_TYPE; - } + return switch (bType.tag) { + case TypeTags.NEVER -> LOAD_NEVER_TYPE; + case TypeTags.INT, TypeTags.UNSIGNED8_INT, TypeTags.UNSIGNED16_INT, TypeTags.UNSIGNED32_INT, + TypeTags.SIGNED8_INT, TypeTags.SIGNED16_INT, TypeTags.SIGNED32_INT -> + LOAD_INTEGER_TYPE; + case TypeTags.FLOAT -> LOAD_FLOAT_TYPE; + case TypeTags.STRING, TypeTags.CHAR_STRING -> LOAD_STRING_TYPE; + case TypeTags.DECIMAL -> LOAD_DECIMAL_TYPE; + case TypeTags.BOOLEAN -> LOAD_BOOLEAN_TYPE; + case TypeTags.BYTE -> LOAD_BYTE_TYPE; + case TypeTags.ANY -> LOAD_ANY_TYPE; + case TypeTags.ANYDATA, TypeTags.REGEXP -> LOAD_ANYDATA_TYPE; + case TypeTags.JSON -> LOAD_JSON_TYPE; + case TypeTags.XML, TypeTags.XML_TEXT -> LOAD_XML_TYPE; + case TypeTags.XML_ELEMENT, TypeTags.XML_PI, TypeTags.XML_COMMENT -> + Symbols.isFlagOn(bType.flags, Flags.READONLY) ? LOAD_TYPE : LOAD_XML_TYPE; + case TypeTags.OBJECT -> Symbols.isService(bType.tsymbol) ? LOAD_SERVICE_TYPE : LOAD_OBJECT_TYPE; + case TypeTags.HANDLE -> LOAD_HANDLE_TYPE; + case TypeTags.READONLY -> LOAD_READONLY_TYPE; + case TypeTags.UNION -> LOAD_UNION_TYPE; + default -> LOAD_TYPE; + }; } } @@ -566,7 +517,7 @@ private String loadTypeClass(BType bType) { * @param bType typedesc type to load */ private void loadTypedescType(MethodVisitor mv, BTypedescType bType) { - // Create an new map type + // Create a new map type mv.visitTypeInsn(NEW, TYPEDESC_TYPE_IMPL); mv.visitInsn(DUP); @@ -585,7 +536,7 @@ private void loadTypedescType(MethodVisitor mv, BTypedescType bType) { * @param bType map type to load */ private void loadMapType(MethodVisitor mv, BMapType bType) { - // Create an new map type + // Create a new map type mv.visitTypeInsn(NEW, MAP_TYPE_IMPL); mv.visitInsn(DUP); @@ -614,7 +565,7 @@ public void loadReadonlyFlag(MethodVisitor mv, BType bType) { * @param bType xml type to load */ private void loadXmlType(MethodVisitor mv, BXMLType bType) { - // Create an new xml type + // Create a new xml type mv.visitTypeInsn(NEW, XML_TYPE_IMPL); mv.visitInsn(DUP); @@ -635,7 +586,7 @@ private void loadXmlType(MethodVisitor mv, BXMLType bType) { * @param bType table type to load */ private void loadTableType(MethodVisitor mv, BTableType bType) { - // Create an new table type + // Create a new table type mv.visitTypeInsn(NEW, TABLE_TYPE_IMPL); mv.visitInsn(DUP); @@ -652,7 +603,7 @@ private void loadTableType(MethodVisitor mv, BTableType bType) { mv.visitInsn(DUP); mv.visitLdcInsn((long) i); mv.visitInsn(L2I); - mv.visitLdcInsn(StringEscapeUtils.unescapeJava(fieldName)); + mv.visitLdcInsn(Utils.unescapeJava(fieldName)); mv.visitInsn(AASTORE); i += 1; } @@ -671,7 +622,7 @@ private void loadTableType(MethodVisitor mv, BTableType bType) { } private void loadStreamType(MethodVisitor mv, BStreamType bType) { - // Create an new stream type + // Create a new stream type mv.visitTypeInsn(NEW, STREAM_TYPE_IMPL); mv.visitInsn(DUP); @@ -722,12 +673,8 @@ public boolean loadUnionName(MethodVisitor mv, BUnionType unionType) { public void loadCyclicFlag(MethodVisitor mv, BType valueType) { valueType = JvmCodeGenUtil.getImpliedType(valueType); switch (valueType.tag) { - case TypeTags.UNION: - mv.visitInsn(((BUnionType) valueType).isCyclic ? ICONST_1 : ICONST_0); - break; - case TypeTags.TUPLE: - mv.visitInsn(((BTupleType) valueType).isCyclic ? ICONST_1 : ICONST_0); - break; + case TypeTags.UNION -> mv.visitInsn(((BUnionType) valueType).isCyclic ? ICONST_1 : ICONST_0); + case TypeTags.TUPLE -> mv.visitInsn(((BTupleType) valueType).isCyclic ? ICONST_1 : ICONST_0); } } @@ -772,22 +719,6 @@ private void generateMethodReturnAndInvoke(MethodVisitor methodVisitor, String c methodVisitor.visitMethodInsn(INVOKESTATIC, className, curMethodName, SET_TYPE_ARRAY, false); } - public void createUnionMembersArray(MethodVisitor mv, Set members) { - generateCreateNewArray(mv, members); - int i = 0; - for (BType memberType : members) { - mv.visitInsn(DUP); - mv.visitLdcInsn((long) i++); - mv.visitInsn(L2I); - - // Load the member type - loadType(mv, memberType); - - // Add the member to the array - mv.visitInsn(AASTORE); - } - } - /** * Generate code to load an instance of the given intersection type to the top of the stack. * @@ -874,7 +805,7 @@ private void loadUserDefinedType(MethodVisitor mv, BType bType) { mv.visitMethodInsn(INVOKESPECIAL, typeOwner, JVM_INIT_METHOD, VOID_METHOD_DESC, false); mv.visitLdcInsn(hash); - mv.visitLdcInsn("Package: " + typeOwner + ", TypeName: " + fieldName + ", Shape: " + shape + ""); + mv.visitLdcInsn("Package: " + typeOwner + ", TypeName: " + fieldName + ", Shape: " + shape); mv.visitMethodInsn(INVOKEVIRTUAL, typeOwner, GET_ANON_TYPE_METHOD, JvmSignatures.GET_ANON_TYPE, false); } else { mv.visitFieldInsn(GETSTATIC, typeOwner, fieldName, GET_TYPE); @@ -939,7 +870,7 @@ public void loadInvokableType(MethodVisitor mv, BInvokableType bType) { loadType(mv, restType); } - // load return type type + // load return type loadType(mv, bType.retType); mv.visitLdcInsn(bType.flags); @@ -1051,49 +982,26 @@ public static String getTypeDesc(BType bType) { return GET_REGEXP; } - switch (bType.tag) { - case TypeTags.BYTE: - return "I"; - case TypeTags.FLOAT: - return "D"; - case TypeTags.BOOLEAN: - return "Z"; - case TypeTags.NIL: - case TypeTags.NEVER: - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.JSON: - case TypeTags.FINITE: - case TypeTags.READONLY: - return GET_OBJECT; - case TypeTags.ARRAY: - case TypeTags.TUPLE: - return GET_ARRAY_VALUE; - case TypeTags.ERROR: - return GET_ERROR_VALUE; - case TypeTags.FUTURE: - return GET_FUTURE_VALUE; - case TypeTags.MAP: - case TypeTags.RECORD: - return GET_MAP_VALUE; - case TypeTags.TYPEDESC: - return GET_TYPEDESC; - case TypeTags.STREAM: - return GET_STREAM_VALUE; - case TypeTags.TABLE: - return GET_TABLE_VALUE; - case TypeTags.DECIMAL: - return GET_BDECIMAL; - case TypeTags.OBJECT: - return GET_BOBJECT; - case TypeTags.HANDLE: - return GET_HANDLE_VALUE; - case TypeTags.INVOKABLE: - return GET_FUNCTION_POINTER; - default: - throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); - } + return switch (bType.tag) { + case TypeTags.BYTE -> "I"; + case TypeTags.FLOAT -> "D"; + case TypeTags.BOOLEAN -> "Z"; + case TypeTags.NIL, TypeTags.NEVER, TypeTags.ANY, TypeTags.ANYDATA, TypeTags.UNION, TypeTags.JSON, + TypeTags.FINITE, TypeTags.READONLY -> + GET_OBJECT; + case TypeTags.ARRAY, TypeTags.TUPLE -> GET_ARRAY_VALUE; + case TypeTags.ERROR -> GET_ERROR_VALUE; + case TypeTags.FUTURE -> GET_FUTURE_VALUE; + case TypeTags.MAP, TypeTags.RECORD -> GET_MAP_VALUE; + case TypeTags.TYPEDESC -> GET_TYPEDESC; + case TypeTags.STREAM -> GET_STREAM_VALUE; + case TypeTags.TABLE -> GET_TABLE_VALUE; + case TypeTags.DECIMAL -> GET_BDECIMAL; + case TypeTags.OBJECT -> GET_BOBJECT; + case TypeTags.HANDLE -> GET_HANDLE_VALUE; + case TypeTags.INVOKABLE -> GET_FUNCTION_POINTER; + default -> throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); + }; } private void loadFiniteType(MethodVisitor mv, BFiniteType finiteType) { @@ -1140,17 +1048,12 @@ private void loadFiniteType(MethodVisitor mv, BFiniteType finiteType) { private void loadValueType(MethodVisitor mv, BType valueType) { valueType = JvmCodeGenUtil.getImpliedType(valueType); switch (valueType.tag) { - case TypeTags.BOOLEAN: - mv.visitMethodInsn(INVOKESTATIC, BOOLEAN_VALUE, VALUE_OF_METHOD, - BOOLEAN_VALUE_OF_METHOD, false); - break; - case TypeTags.FLOAT: - mv.visitMethodInsn(INVOKESTATIC, DOUBLE_VALUE, VALUE_OF_METHOD, - DOUBLE_VALUE_OF_METHOD, false); - break; - case TypeTags.BYTE: - mv.visitMethodInsn(INVOKESTATIC, INT_VALUE, VALUE_OF_METHOD, - INT_VALUE_OF_METHOD, false); + case TypeTags.BOOLEAN -> mv.visitMethodInsn(INVOKESTATIC, BOOLEAN_VALUE, VALUE_OF_METHOD, + BOOLEAN_VALUE_OF_METHOD, false); + case TypeTags.FLOAT -> mv.visitMethodInsn(INVOKESTATIC, DOUBLE_VALUE, VALUE_OF_METHOD, + DOUBLE_VALUE_OF_METHOD, false); + case TypeTags.BYTE -> mv.visitMethodInsn(INVOKESTATIC, INT_VALUE, VALUE_OF_METHOD, + INT_VALUE_OF_METHOD, false); } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmValueGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmValueGen.java index ad1a99d6ea3b..f0802f68060d 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmValueGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/JvmValueGen.java @@ -17,22 +17,19 @@ */ package org.wso2.ballerinalang.compiler.bir.codegen; -import io.ballerina.identifier.Utils; import org.ballerinalang.model.elements.PackageID; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.wso2.ballerinalang.compiler.bir.codegen.internal.AsyncDataCollector; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JFieldBIRFunction; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JMethodBIRFunction; import org.wso2.ballerinalang.compiler.bir.codegen.methodgen.InitMethodGen; -import org.wso2.ballerinalang.compiler.bir.codegen.methodgen.LambdaGen; import org.wso2.ballerinalang.compiler.bir.codegen.methodgen.MethodGen; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JFieldBIRFunction; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JMethodBIRFunction; import org.wso2.ballerinalang.compiler.bir.codegen.split.JvmConstantsGen; import org.wso2.ballerinalang.compiler.bir.codegen.split.values.JvmObjectGen; import org.wso2.ballerinalang.compiler.bir.codegen.split.values.JvmRecordGen; -import org.wso2.ballerinalang.compiler.bir.model.BIRInstruction; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; import org.wso2.ballerinalang.compiler.bir.model.BIRNode.BIRFunction; import org.wso2.ballerinalang.compiler.semantics.analyzer.TypeHashVisitor; @@ -43,7 +40,6 @@ import org.wso2.ballerinalang.compiler.semantics.model.types.BObjectType; import org.wso2.ballerinalang.compiler.semantics.model.types.BRecordType; import org.wso2.ballerinalang.compiler.semantics.model.types.BType; -import org.wso2.ballerinalang.compiler.util.Names; import org.wso2.ballerinalang.compiler.util.TypeTags; import org.wso2.ballerinalang.util.Flags; @@ -54,7 +50,6 @@ import static org.objectweb.asm.Opcodes.ACC_FINAL; import static org.objectweb.asm.Opcodes.ACC_PROTECTED; import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -import static org.objectweb.asm.Opcodes.ACC_STATIC; import static org.objectweb.asm.Opcodes.ACC_SUPER; import static org.objectweb.asm.Opcodes.ALOAD; import static org.objectweb.asm.Opcodes.ARETURN; @@ -82,7 +77,6 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CLASS_FILE_SUFFIX; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.INSTANTIATE_FUNCTION; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.JVM_INIT_METHOD; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.JVM_STATIC_INIT_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.LOCK_VALUE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MAP_VALUE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MAP_VALUE_IMPL; @@ -124,8 +118,6 @@ */ public class JvmValueGen { - static final String ENCODED_RECORD_INIT = - Utils.encodeFunctionIdentifier(Names.INIT_FUNCTION_SUFFIX.value); private final BIRNode.BIRPackage module; private final JvmPackageGen jvmPackageGen; private final MethodGen methodGen; @@ -147,25 +139,22 @@ public class JvmValueGen { this.types = types; } - static void injectDefaultParamInitsToAttachedFuncs(BIRNode.BIRPackage module, InitMethodGen initMethodGen, - JvmPackageGen jvmPackageGen) { + static void injectDefaultParamInitsToAttachedFuncs(BIRNode.BIRPackage module, InitMethodGen initMethodGen) { List typeDefs = module.typeDefs; for (BIRNode.BIRTypeDefinition optionalTypeDef : typeDefs) { BType bType = JvmCodeGenUtil.getImpliedType(optionalTypeDef.type); if ((bType.tag == TypeTags.OBJECT && Symbols.isFlagOn( bType.tsymbol.flags, Flags.CLASS)) || bType.tag == TypeTags.RECORD) { - desugarObjectMethods(optionalTypeDef.attachedFuncs, initMethodGen, - jvmPackageGen); + desugarObjectMethods(optionalTypeDef.attachedFuncs, initMethodGen); } } } - private static void desugarObjectMethods(List attachedFuncs, InitMethodGen initMethodGen, - JvmPackageGen jvmPackageGen) { + private static void desugarObjectMethods(List attachedFuncs, InitMethodGen initMethodGen) { for (BIRNode.BIRFunction birFunc : attachedFuncs) { if (JvmCodeGenUtil.isExternFunc(birFunc)) { - if (birFunc instanceof JMethodBIRFunction) { - desugarInteropFuncs((JMethodBIRFunction) birFunc, initMethodGen); + if (birFunc instanceof JMethodBIRFunction jMethodBIRFunction) { + desugarInteropFuncs(jMethodBIRFunction, initMethodGen); initMethodGen.resetIds(); } else if (!(birFunc instanceof JFieldBIRFunction)) { initMethodGen.resetIds(); @@ -193,7 +182,8 @@ public static boolean isOptionalRecordField(BField field) { return (field.symbol.flags & BAL_OPTIONAL) == BAL_OPTIONAL; } - void generateValueClasses(Map jarEntries, JvmConstantsGen jvmConstantsGen, JvmTypeGen jvmTypeGen) { + void generateValueClasses(JarEntries jarEntries, JvmConstantsGen jvmConstantsGen, JvmTypeGen jvmTypeGen, + AsyncDataCollector asyncDataCollector) { String packageName = JvmCodeGenUtil.getPackageName(module.packageID); module.typeDefs.forEach(optionalTypeDef -> { if (optionalTypeDef.type.tag == TypeTags.TYPEREFDESC) { @@ -201,7 +191,9 @@ void generateValueClasses(Map jarEntries, JvmConstantsGen jvmCon } BType bType = optionalTypeDef.type; String className = getTypeValueClassName(packageName, optionalTypeDef.internalName.value); - AsyncDataCollector asyncDataCollector = new AsyncDataCollector(className); + String valueClass = VALUE_CLASS_PREFIX + optionalTypeDef.internalName.value; + asyncDataCollector.setCurrentSourceFileName(valueClass); + asyncDataCollector.setCurrentSourceFileWithoutExt(valueClass); if (optionalTypeDef.type.tag == TypeTags.OBJECT && Symbols.isFlagOn(optionalTypeDef.type.tsymbol.flags, Flags.CLASS)) { BObjectType objectType = (BObjectType) optionalTypeDef.type; @@ -209,8 +201,8 @@ void generateValueClasses(Map jarEntries, JvmConstantsGen jvmCon asyncDataCollector, jarEntries); } else if (bType.tag == TypeTags.RECORD) { BRecordType recordType = (BRecordType) bType; - byte[] bytes = this.createRecordValueClass(recordType, className, optionalTypeDef, jvmConstantsGen - , asyncDataCollector, jvmTypeGen); + byte[] bytes = this.createRecordValueClass(recordType, className, optionalTypeDef, + asyncDataCollector, jvmTypeGen); jarEntries.put(className + CLASS_FILE_SUFFIX, bytes); String typedescClass = getTypeDescClassName(packageName, optionalTypeDef.internalName.value); bytes = this.createRecordTypeDescClass(recordType, typedescClass, optionalTypeDef, jvmTypeGen); @@ -277,18 +269,15 @@ private void createInstantiateMethodWithInitialValues(ClassWriter cw, BRecordTyp mv.visitInsn(POP); // Invoke the init-function of this type. - String initFuncName; String valueClassName; List attachedFuncs = typeDef.attachedFuncs; // Attached functions are empty for type-labeling. In such cases, call the init() of the original type value if (!attachedFuncs.isEmpty()) { - initFuncName = attachedFuncs.get(0).name.value; valueClassName = className; } else { // record type is the original record-type of this type-label valueClassName = getTypeValueClassName(recordType.tsymbol.pkgID, toNameString(recordType)); - initFuncName = recordType.name + ENCODED_RECORD_INIT; } mv.visitInsn(DUP); @@ -308,8 +297,7 @@ public static String getTypeValueClassName(PackageID packageID, String typeName) } private byte[] createRecordValueClass(BRecordType recordType, String className, BIRNode.BIRTypeDefinition typeDef, - JvmConstantsGen jvmConstantsGen, AsyncDataCollector asyncDataCollector, - JvmTypeGen jvmTypeGen) { + AsyncDataCollector asyncDataCollector, JvmTypeGen jvmTypeGen) { ClassWriter cw = new BallerinaClassWriter(COMPUTE_FRAMES); if (typeDef.pos != null) { cw.visitSource(typeDef.pos.lineRange().fileName(), null); @@ -317,7 +305,6 @@ private byte[] createRecordValueClass(BRecordType recordType, String className, cw.visitSource(className, null); } JvmCastGen jvmCastGen = new JvmCastGen(jvmPackageGen.symbolTable, jvmTypeGen, types); - LambdaGen lambdaGen = new LambdaGen(jvmPackageGen, jvmCastGen); cw.visit(V17, ACC_PUBLIC + ACC_SUPER + ACC_FINAL, className, RECORD_VALUE_CLASS, MAP_VALUE_IMPL, new String[]{MAP_VALUE}); @@ -334,11 +321,8 @@ private byte[] createRecordValueClass(BRecordType recordType, String className, jvmRecordGen.createAndSplitGetKeysMethod(cw, fields, className); this.createRecordPopulateInitialValuesMethod(cw, className); - this.createRecordConstructor(cw, INIT_TYPEDESC, className, typeDef, recordType); - this.createRecordConstructor(cw, TYPE_PARAMETER, className, typeDef, recordType); - this.createLambdas(cw, asyncDataCollector, lambdaGen, className); - JvmCodeGenUtil.visitStrandMetadataFields(cw, asyncDataCollector.getStrandMetadata()); - this.generateStaticInitializer(cw, className, module.packageID, asyncDataCollector); + this.createRecordConstructor(cw, INIT_TYPEDESC, className); + this.createRecordConstructor(cw, TYPE_PARAMETER, className); cw.visitEnd(); return jvmPackageGen.getBytes(cw, typeDef); @@ -365,8 +349,8 @@ private void createTypeDescConstructor(ClassWriter cw, String className) { } private void createTypeDescConstructorWithAnnotations(ClassWriter cw, String name) { - String descriptor = TYPE_DESC_CONSTRUCTOR_WITH_ANNOTATIONS; - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, JVM_INIT_METHOD, descriptor, null, null); + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, JVM_INIT_METHOD, TYPE_DESC_CONSTRUCTOR_WITH_ANNOTATIONS, null, + null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); @@ -389,8 +373,7 @@ private void createTypeDescConstructorWithAnnotations(ClassWriter cw, String nam mv.visitEnd(); } - private void createRecordConstructor(ClassWriter cw, String argumentClass, String className, - BIRNode.BIRTypeDefinition typedef, BRecordType recordType) { + private void createRecordConstructor(ClassWriter cw, String argumentClass, String className) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, JVM_INIT_METHOD, argumentClass, null, null); mv.visitCode(); @@ -472,14 +455,13 @@ private void createRecordPopulateInitialValuesMethod(ClassWriter cw, String clas private void createObjectValueClasses(BObjectType objectType, String className, BIRNode.BIRTypeDefinition typeDef, JvmConstantsGen jvmConstantsGen, AsyncDataCollector asyncDataCollector, - Map jarEntries) { + JarEntries jarEntries) { ClassWriter cw = new BallerinaClassWriter(COMPUTE_FRAMES); cw.visitSource(typeDef.pos.lineRange().fileName(), null); SymbolTable symbolTable = jvmPackageGen.symbolTable; JvmTypeGen jvmTypeGen = new JvmTypeGen(jvmConstantsGen, module.packageID, typeHashVisitor, symbolTable); JvmCastGen jvmCastGen = new JvmCastGen(symbolTable, jvmTypeGen, types); - LambdaGen lambdaGen = new LambdaGen(jvmPackageGen, jvmCastGen); cw.visit(V17, ACC_PUBLIC + ACC_SUPER, className, null, ABSTRACT_OBJECT_VALUE, new String[]{B_OBJECT}); Map fields = objectType.fields; @@ -499,9 +481,6 @@ private void createObjectValueClasses(BObjectType objectType, String className, jvmObjectGen.createAndSplitGetMethod(cw, fields, className, jvmCastGen); jvmObjectGen.createAndSplitSetMethod(cw, fields, className, jvmCastGen); jvmObjectGen.createAndSplitSetOnInitializationMethod(cw, fields, className); - this.createLambdas(cw, asyncDataCollector, lambdaGen, className); - JvmCodeGenUtil.visitStrandMetadataFields(cw, asyncDataCollector.getStrandMetadata()); - this.generateStaticInitializer(cw, className, module.packageID, asyncDataCollector); cw.visitEnd(); jarEntries.put(className + CLASS_FILE_SUFFIX, jvmPackageGen.getBytes(cw, typeDef)); } @@ -535,7 +514,7 @@ private void createObjectMethodsWithSplitClasses(ClassWriter cw, List jarEntries) { + JarEntries jarEntries) { int splitClassNum = 1; ClassWriter splitCW = new BallerinaClassWriter(COMPUTE_FRAMES); splitCW.visitSource(typeDef.pos.lineRange().fileName(), null); @@ -608,25 +587,6 @@ private void createObjectInit(ClassWriter cw, Map fields, String mv.visitEnd(); } - private void createLambdas(ClassWriter cw, AsyncDataCollector asyncDataCollector, - LambdaGen lambdaGen, String className) { - for (Map.Entry entry : asyncDataCollector.getLambdas().entrySet()) { - lambdaGen.generateLambdaMethod(entry.getValue(), cw, entry.getKey(), className); - } - } - - private void generateStaticInitializer(ClassWriter cw, String moduleClass, PackageID module, - AsyncDataCollector asyncDataCollector) { - if (asyncDataCollector.getStrandMetadata().isEmpty()) { - return; - } - MethodVisitor mv = cw.visitMethod(ACC_STATIC, JVM_STATIC_INIT_METHOD, VOID_METHOD_DESC, null, null); - JvmCodeGenUtil.generateStrandMetadata(mv, moduleClass, module, asyncDataCollector); - mv.visitInsn(RETURN); - JvmCodeGenUtil.visitMaxStackForMethod(mv, JVM_STATIC_INIT_METHOD, moduleClass); - mv.visitEnd(); - } - private void createRecordClearMethod(ClassWriter cw, String className) { // throw an UnsupportedOperationException, since clear is not supported by for records. MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "clear", VOID_METHOD_DESC, null, null); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/ShutDownListenerGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/ShutDownListenerGen.java index 5a617d40caf5..440ca2ee2b2c 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/ShutDownListenerGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/ShutDownListenerGen.java @@ -22,8 +22,6 @@ import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; -import java.util.Map; - import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; import static org.objectweb.asm.Opcodes.ACC_PRIVATE; import static org.objectweb.asm.Opcodes.ACC_PUBLIC; @@ -36,9 +34,9 @@ import static org.objectweb.asm.Opcodes.RETURN; import static org.objectweb.asm.Opcodes.V17; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CLASS_FILE_SUFFIX; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CURRENT_MODULE_STOP; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.JAVA_THREAD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.JVM_INIT_METHOD; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_STOP_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.RUNTIME_REGISTRY_VARIABLE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_RUNTIME_REGISTRY; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_RUNTIME_REGISTRY; @@ -50,11 +48,12 @@ * @since 2.0.0 */ public class ShutDownListenerGen { - void generateShutdownSignalListener(String initClass, Map jarEntries) { + + void generateShutdownSignalListener(String initClass, JarEntries jarEntries) { String innerClassName = initClass + "$SignalListener"; ClassWriter cw = new BallerinaClassWriter(COMPUTE_FRAMES); cw.visit(V17, ACC_SUPER, innerClassName, null, JAVA_THREAD, null); - FieldVisitor fv = cw.visitField(ACC_PRIVATE , RUNTIME_REGISTRY_VARIABLE, + FieldVisitor fv = cw.visitField(ACC_PRIVATE, RUNTIME_REGISTRY_VARIABLE, GET_RUNTIME_REGISTRY, null, null); fv.visitEnd(); @@ -75,8 +74,7 @@ private void genConstructor(String innerClassName, ClassWriter cw) { mv.visitMethodInsn(INVOKESPECIAL, JAVA_THREAD, JVM_INIT_METHOD, VOID_METHOD_DESC, false); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); - mv.visitFieldInsn(PUTFIELD, innerClassName , RUNTIME_REGISTRY_VARIABLE, - GET_RUNTIME_REGISTRY); + mv.visitFieldInsn(PUTFIELD, innerClassName, RUNTIME_REGISTRY_VARIABLE, GET_RUNTIME_REGISTRY); mv.visitInsn(RETURN); JvmCodeGenUtil.visitMaxStackForMethod(mv, JVM_INIT_METHOD, innerClassName); mv.visitEnd(); @@ -85,11 +83,11 @@ private void genConstructor(String innerClassName, ClassWriter cw) { private void genRunMethod(String initClass, String innerClassName, ClassWriter cw) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "run", VOID_METHOD_DESC, null, null); mv.visitCode(); + // Create a scheduler. A new scheduler is used here, to make the stop function to not + // depend/wait on whatever is being running on the background. eg: a busy loop in the main. mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, innerClassName , RUNTIME_REGISTRY_VARIABLE, - GET_RUNTIME_REGISTRY); - mv.visitMethodInsn(INVOKESTATIC, initClass, MODULE_STOP_METHOD, - INIT_RUNTIME_REGISTRY, false); + mv.visitFieldInsn(GETFIELD, innerClassName, RUNTIME_REGISTRY_VARIABLE, GET_RUNTIME_REGISTRY); + mv.visitMethodInsn(INVOKESTATIC, initClass, CURRENT_MODULE_STOP, JvmSignatures.CURRENT_MODULE_STOP, false); mv.visitInsn(RETURN); JvmCodeGenUtil.visitMaxStackForMethod(mv, "run", innerClassName); mv.visitEnd(); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JInteropException.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/exceptions/JInteropException.java similarity index 81% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JInteropException.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/exceptions/JInteropException.java index 5b60cd469cca..3b6f8e382f72 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JInteropException.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/exceptions/JInteropException.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.exceptions; import io.ballerina.tools.diagnostics.DiagnosticCode; @@ -26,15 +26,15 @@ */ public class JInteropException extends RuntimeException { - private DiagnosticCode code; + private final DiagnosticCode code; - JInteropException(DiagnosticCode code, String message) { + public JInteropException(DiagnosticCode code, String message) { super(message); this.code = code; } - JInteropException(DiagnosticCode code, String message, Throwable cause) { + public JInteropException(DiagnosticCode code, String message, Throwable cause) { super(message, cause); this.code = code; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/AsyncDataCollector.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/AsyncDataCollector.java index 3225b52b34ae..75fd86acb445 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/AsyncDataCollector.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/AsyncDataCollector.java @@ -17,11 +17,19 @@ */ package org.wso2.ballerinalang.compiler.bir.codegen.internal; +import io.ballerina.identifier.Utils; +import org.ballerinalang.model.elements.PackageID; import org.wso2.ballerinalang.compiler.bir.model.BIRInstruction; +import org.wso2.ballerinalang.compiler.bir.model.BIRNode; import java.util.HashMap; import java.util.Map; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil.getModuleLevelClassName; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.LAMBDA_PREFIX; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MAX_GENERATED_LAMBDAS_PER_CLASS; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_LAMBDAS_CLASS_NAME; + /** * A data holder to keep async invocation related data which will be used by class generation. * @@ -29,41 +37,55 @@ */ public class AsyncDataCollector { - private Map lambdas; - private Map strandMetaDataMap; + private final Map lambdas; + private final Map strandMetaDataMap; + private final PackageID packageID; + private String currentSourceFileWithoutExt = null; + private String currentSourceFileName = null; + private int classIndex = 0; private int lambdaIndex = 0; - private String enclosingClass; - - public AsyncDataCollector(String enclosingClass) { - - this.enclosingClass = enclosingClass; - lambdas = new HashMap<>(); - strandMetaDataMap = new HashMap<>(); - } - - public void incrementLambdaIndex() { - lambdaIndex++; + public AsyncDataCollector(BIRNode.BIRPackage module) { + this.lambdas = new HashMap<>(); + this.strandMetaDataMap = new HashMap<>(); + this.packageID = module.packageID; } - public int getLambdaIndex() { - - return lambdaIndex; + public LambdaFunction addAndGetLambda(String funcName, BIRInstruction inst, boolean isAsync) { + String encodedFuncName = Utils.encodeFunctionIdentifier(funcName); + String enclosingClass = getModuleLevelClassName(packageID, MODULE_LAMBDAS_CLASS_NAME + classIndex, + currentSourceFileWithoutExt, "/"); + LambdaClass lambdaClass = lambdas.get(enclosingClass); + if (lambdaClass == null || lambdaClass.lambdaFunctionList.size() > MAX_GENERATED_LAMBDAS_PER_CLASS) { + enclosingClass = getModuleLevelClassName(packageID, MODULE_LAMBDAS_CLASS_NAME + ++classIndex, + currentSourceFileWithoutExt, "/"); + lambdaClass = new LambdaClass(currentSourceFileName); + lambdas.put(enclosingClass, lambdaClass); + lambdaIndex = 0; + } + String lambdaName; + // We need to differentiate FP value and Async call for debugger purpose, hence using different names for + // generated lambdas. + if (isAsync) { + lambdaName = encodedFuncName + LAMBDA_PREFIX + lambdaIndex++ + "$"; + } else { + lambdaName = encodedFuncName + "$lambda" + lambdaIndex++ + "$"; + } + LambdaFunction lambdaFunction = new LambdaFunction(lambdaName, enclosingClass, inst); + lambdaClass.lambdaFunctionList.add(lambdaFunction); + return lambdaFunction; } - public void add(String lambdaName, BIRInstruction callInstruction) { - - lambdas.put(lambdaName, callInstruction); + public Map getLambdaClasses() { + return lambdas; } - public String getEnclosingClass() { - - return enclosingClass; + public void setCurrentSourceFileName(String currentSourceFileName) { + this.currentSourceFileName = currentSourceFileName; } - public Map getLambdas() { - - return lambdas; + public void setCurrentSourceFileWithoutExt(String currentSourceFileWithoutExt) { + this.currentSourceFileWithoutExt = currentSourceFileWithoutExt; } public Map getStrandMetadata() { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/BIRVarToJVMIndexMap.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/BIRVarToJVMIndexMap.java index e9413b2c9de2..b69ac828c469 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/BIRVarToJVMIndexMap.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/BIRVarToJVMIndexMap.java @@ -18,8 +18,8 @@ package org.wso2.ballerinalang.compiler.bir.codegen.internal; import org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JType; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JType; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags; import org.wso2.ballerinalang.compiler.semantics.model.types.BType; import org.wso2.ballerinalang.compiler.util.TypeTags; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/FunctionParamComparator.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/FunctionParamComparator.java index 82911c9344e6..55bb1b2450d0 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/FunctionParamComparator.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/FunctionParamComparator.java @@ -42,15 +42,11 @@ public int compare(BIRNode.BIRVariableDcl o1, BIRNode.BIRVariableDcl o2) { private int getWeight(BIRNode.BIRVariableDcl variableDcl) { - switch (variableDcl.kind) { - case RETURN: - return 1; - case ARG: - return 2; - case TEMP: - return 3; - default: - return 4; - } + return switch (variableDcl.kind) { + case RETURN -> 1; + case ARG -> 2; + case TEMP -> 3; + default -> 4; + }; } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/JavaClass.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/JavaClass.java index 7994b0c023b9..23844c3b6f92 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/JavaClass.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/JavaClass.java @@ -30,11 +30,13 @@ public class JavaClass { public final String sourceFileName; + public final String cleanedBalFileName; public final List functions; - public JavaClass(String sourceFileName) { + public JavaClass(String sourceFileName, String cleanedBalFileName) { this.sourceFileName = sourceFileName; + this.cleanedBalFileName = cleanedBalFileName; this.functions = new ArrayList<>(); } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/LabelGenerator.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/LabelGenerator.java index d7cd051e324c..e0b9d3ab7869 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/LabelGenerator.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/LabelGenerator.java @@ -29,7 +29,7 @@ */ public class LabelGenerator { - private Map bbLabels = new HashMap<>(); + private final Map bbLabels = new HashMap<>(); public Label getLabel(String labelKey) { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/LambdaClass.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/LambdaClass.java new file mode 100644 index 000000000000..c046d9b1307b --- /dev/null +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/LambdaClass.java @@ -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. + */ + +package org.wso2.ballerinalang.compiler.bir.codegen.internal; + +import java.util.ArrayList; +import java.util.List; + +/** + * A data holder to information of lambda function. + * + * @since 2201.10.0 + */ +public class LambdaClass { + + public String sourceFileName; + + public List lambdaFunctionList; + + public LambdaClass(String sourceFileName) { + this.sourceFileName = sourceFileName; + this.lambdaFunctionList = new ArrayList<>(); + } +} diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/LambdaFunction.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/LambdaFunction.java new file mode 100644 index 000000000000..dafa768063df --- /dev/null +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/internal/LambdaFunction.java @@ -0,0 +1,41 @@ +/* + * 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 org.wso2.ballerinalang.compiler.bir.codegen.internal; + +import org.wso2.ballerinalang.compiler.bir.model.BIRInstruction; + +/** + * A data holder to information of lambda function. + * + * @since 2201.10.0 + */ +public class LambdaFunction { + + public String lambdaName; + + public String enclosingClass; + + public BIRInstruction callInstruction; + + public LambdaFunction(String lambdaName, String enclosingClass, BIRInstruction callInstruction) { + this.lambdaName = lambdaName; + this.enclosingClass = enclosingClass; + this.callInstruction = callInstruction; + } +} diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/AnnotationProc.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/AnnotationProc.java index 48c7ff3b7f50..bba8a1a8a9b1 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/AnnotationProc.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/AnnotationProc.java @@ -18,6 +18,7 @@ package org.wso2.ballerinalang.compiler.bir.codegen.interop; import org.ballerinalang.compiler.BLangCompilerException; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JType; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; import org.wso2.ballerinalang.compiler.bir.model.BIRNode.BIRAnnotationAttachment; import org.wso2.ballerinalang.compiler.bir.model.BIRNode.BIRFunction; @@ -34,22 +35,24 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JInterop.getMethodKindFromAnnotTag; import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JInterop.isInteropAnnotationTag; import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JInterop.isMethodAnnotationTag; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JType.getJArrayTypeFromTypeName; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JType.getJTypeFromTypeName; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JType.getJArrayTypeFromTypeName; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JType.getJTypeFromTypeName; /** * JInterop related annotation processing methods. * * @since 1.2.0 */ -public class AnnotationProc { +public final class AnnotationProc { public static final String NAME_FIELD_NAME = "name"; public static final String CLASS_FIELD_NAME = "class"; - public static final String FIELD_METHOD_FIELD_NAME = "method"; public static final String PARAM_TYPES_FIELD_NAME = "paramTypes"; public static final String DIMENSIONS_FIELD_NAME = "dimensions"; + private AnnotationProc() { + } + static InteropValidationRequest getInteropAnnotValue(BIRFunction birFunc) { BIRAnnotationAttachment annotAttach = getInteropAnnotAttachment(birFunc); @@ -135,13 +138,13 @@ private static List buildParamTypeConstraints(BIRNode.ConstValue annotVal for (BIRNode.ConstValue annotArrayElement : annotArrayElements) { JType jType; Object elementValue = annotArrayElement.value; - if (elementValue instanceof String) { - jType = getJTypeFromTypeName((String) elementValue); - } else if (elementValue instanceof Map) { - Map annotValueMap = (Map) elementValue; - String elementClass = (String) getLiteralValueFromAnnotValue(annotValueMap.get(CLASS_FIELD_NAME)); - byte dimensions = ((Long) getLiteralValueFromAnnotValue(annotValueMap.get(DIMENSIONS_FIELD_NAME))) - .byteValue(); + if (elementValue instanceof String s) { + jType = getJTypeFromTypeName(s); + } else if (elementValue instanceof Map annotValueMap) { + String elementClass = (String) getLiteralValueFromAnnotValue( + (BIRNode.ConstValue) annotValueMap.get(CLASS_FIELD_NAME)); + byte dimensions = ((Long) getLiteralValueFromAnnotValue( + (BIRNode.ConstValue) annotValueMap.get(DIMENSIONS_FIELD_NAME))).byteValue(); jType = getJArrayTypeFromTypeName(elementClass, dimensions); } else { throw new BLangCompilerException("unexpected annotation value: " + annotArrayElement); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/ExternalMethodGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/ExternalMethodGen.java index 821a0b48e45c..5d25387eb63e 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/ExternalMethodGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/ExternalMethodGen.java @@ -26,6 +26,9 @@ import org.wso2.ballerinalang.compiler.bir.codegen.internal.AsyncDataCollector; import org.wso2.ballerinalang.compiler.bir.codegen.methodgen.InitMethodGen; import org.wso2.ballerinalang.compiler.bir.codegen.methodgen.MethodGen; +import org.wso2.ballerinalang.compiler.bir.codegen.model.BIRFunctionWrapper; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JFieldBIRFunction; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JMethodBIRFunction; import org.wso2.ballerinalang.compiler.bir.codegen.split.JvmConstantsGen; import org.wso2.ballerinalang.compiler.bir.model.BIRNode.BIRFunction; import org.wso2.ballerinalang.compiler.bir.model.BIRNode.BIRPackage; @@ -44,15 +47,15 @@ * * @since 1.2.0 */ -public class ExternalMethodGen { +public final class ExternalMethodGen { public static void genJMethodForBExternalFunc(BIRFunction birFunc, ClassWriter cw, BIRPackage birModule, BType attachedType, MethodGen methodGen, JvmPackageGen jvmPackageGen, JvmTypeGen jvmTypeGen, JvmCastGen jvmCastGen, JvmConstantsGen jvmConstantsGen, String moduleClassName, AsyncDataCollector lambdaGenMetadata, Types types) { - if (birFunc instanceof JFieldBIRFunction) { - genJFieldForInteropField((JFieldBIRFunction) birFunc, cw, birModule.packageID, jvmPackageGen, jvmTypeGen, + if (birFunc instanceof JFieldBIRFunction jFieldBIRFunction) { + genJFieldForInteropField(jFieldBIRFunction, cw, birModule.packageID, jvmPackageGen, jvmTypeGen, jvmCastGen, jvmConstantsGen, lambdaGenMetadata, types); } else { methodGen.genJMethodForBFunc(birFunc, cw, birModule, jvmTypeGen, jvmCastGen, jvmConstantsGen, @@ -70,8 +73,8 @@ public static void injectDefaultParamInits(BIRPackage module, InitMethodGen init while (count < funcSize) { BIRFunction birFunc = functions.get(count); count = count + 1; - if (birFunc instanceof JMethodBIRFunction) { - desugarInteropFuncs((JMethodBIRFunction) birFunc, initMethodGen); + if (birFunc instanceof JMethodBIRFunction jMethodBIRFunction) { + desugarInteropFuncs(jMethodBIRFunction, initMethodGen); initMethodGen.resetIds(); } else if (!(birFunc instanceof JFieldBIRFunction)) { initMethodGen.resetIds(); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/InteropMethodGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/InteropMethodGen.java index 9d6c9fb3446c..4d30424e3221 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/InteropMethodGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/InteropMethodGen.java @@ -34,6 +34,18 @@ import org.wso2.ballerinalang.compiler.bir.codegen.internal.BIRVarToJVMIndexMap; import org.wso2.ballerinalang.compiler.bir.codegen.internal.LabelGenerator; import org.wso2.ballerinalang.compiler.bir.codegen.methodgen.InitMethodGen; +import org.wso2.ballerinalang.compiler.bir.codegen.model.CatchIns; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JCast; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JErrorEntry; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JFieldBIRFunction; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JIConstructorCall; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JIMethodCall; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JMethod; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JMethodBIRFunction; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JMethodKind; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JType; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JavaField; import org.wso2.ballerinalang.compiler.bir.codegen.split.JvmConstantsGen; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; import org.wso2.ballerinalang.compiler.bir.model.BIRNode.BIRBasicBlock; @@ -116,7 +128,7 @@ * * @since 1.2.0 */ -public class InteropMethodGen { +public final class InteropMethodGen { static void genJFieldForInteropField(JFieldBIRFunction birFunc, ClassWriter classWriter, PackageID birModule, JvmPackageGen jvmPackageGen, JvmTypeGen jvmTypeGen, JvmCastGen jvmCastGen, @@ -141,7 +153,7 @@ static void genJFieldForInteropField(JFieldBIRFunction birFunc, ClassWriter clas JvmErrorGen errorGen = new JvmErrorGen(mv, indexMap, instGen); LabelGenerator labelGen = new LabelGenerator(); JvmTerminatorGen termGen = new JvmTerminatorGen(mv, indexMap, labelGen, errorGen, birModule, instGen, - jvmPackageGen, jvmTypeGen, jvmCastGen, asyncDataCollector); + jvmPackageGen, jvmTypeGen, jvmCastGen, jvmConstantsGen, asyncDataCollector); mv.visitCode(); Label paramLoadLabel = labelGen.getLabel("param_load"); @@ -152,8 +164,7 @@ static void genJFieldForInteropField(JFieldBIRFunction birFunc, ClassWriter clas // the JVM method local variable index for each parameter is assigned List birFuncParams = new ArrayList<>(); for (BIRVariableDcl birLocalVarOptional : birFunc.localVars) { - if (birLocalVarOptional instanceof BIRNode.BIRFunctionParameter) { - BIRNode.BIRFunctionParameter functionParameter = (BIRNode.BIRFunctionParameter) birLocalVarOptional; + if (birLocalVarOptional instanceof BIRNode.BIRFunctionParameter functionParameter) { birFuncParams.add(functionParameter); indexMap.addIfNotExists(functionParameter.name.value, functionParameter.type); } @@ -256,7 +267,7 @@ public static void desugarInteropFuncs(JMethodBIRFunction birFunc, InitMethodGen Class[] jMethodParamTypes = jMethod.getParamTypes(); JType jMethodRetType = JInterop.getJType(jMethod.getReturnType()); - if (jMethodRetType == JType.jVoid && jMethod.isBalEnvAcceptingMethod()) { + if (jMethodRetType == JType.J_VOID && jMethod.isBalEnvAcceptingMethod()) { jMethodRetType = JType.getJTypeForBType(birFunc.returnVariable.type); } @@ -369,7 +380,7 @@ public static void desugarInteropFuncs(JMethodBIRFunction birFunc, InitMethodGen if (JvmCodeGenUtil.getImpliedType(retType).tag != TypeTags.NIL) { BIROperand retRef = new BIROperand(birFunc.localVars.get(0)); - if (JType.jVoid != jMethodRetType) { + if (JType.J_VOID != jMethodRetType) { BIRVariableDcl retJObjectVarDcl = new BIRVariableDcl(jMethodRetType, new Name("$_ret_jobject_var_$"), null, VarKind.LOCAL); birFunc.localVars.add(retJObjectVarDcl); @@ -384,7 +395,7 @@ public static void desugarInteropFuncs(JMethodBIRFunction birFunc, InitMethodGen BIRBasicBlock catchBB = new BIRBasicBlock(getNextDesugarBBId(initMethodGen)); JErrorEntry ee = new JErrorEntry(beginBB, thenBB, retRef, catchBB); - for (Class exception : birFunc.jMethod.getExceptionTypes()) { + for (Class exception : birFunc.jMethod.getExceptionTypes()) { BIRTerminator.Return exceptionRet = new BIRTerminator.Return(birFunc.pos); CatchIns catchIns = new CatchIns(); catchIns.errorClass = exception.getName().replace(".", "/"); @@ -444,19 +455,19 @@ private static boolean isMatchingBAndJType(BType sourceType, JType targetType) { // here. We can improve following logic with a type lattice. private static void performWideningPrimitiveConversion(MethodVisitor mv, BType bType, JType jType) { int typeTag = JvmCodeGenUtil.getImpliedType(bType).tag; - if (TypeTags.isIntegerTypeTag(typeTag) && jType.jTag == JTypeTags.JLONG) { - // NOP - } else if (typeTag == TypeTags.FLOAT && jType.jTag == JTypeTags.JDOUBLE) { - // NOP - } else if (TypeTags.isIntegerTypeTag(typeTag)) { - mv.visitInsn(I2L); - } else if (typeTag == TypeTags.FLOAT) { - if (jType.jTag == JTypeTags.JLONG) { - mv.visitInsn(L2D); - } else if (jType.jTag == JTypeTags.JFLOAT) { - mv.visitInsn(F2D); - } else { - mv.visitInsn(I2D); + if (!TypeTags.isIntegerTypeTag(typeTag) || jType.jTag != JTypeTags.JLONG) { + if (typeTag != TypeTags.FLOAT || jType.jTag != JTypeTags.JDOUBLE) { + if (TypeTags.isIntegerTypeTag(typeTag)) { + mv.visitInsn(I2L); + } else if (typeTag == TypeTags.FLOAT) { + if (jType.jTag == JTypeTags.JLONG) { + mv.visitInsn(L2D); + } else if (jType.jTag == JTypeTags.JFLOAT) { + mv.visitInsn(F2D); + } else { + mv.visitInsn(I2D); + } + } } } } @@ -480,26 +491,17 @@ public static String getJTypeSignature(JType jType) { return "[" + getJTypeSignature(eType); } - switch (jType.jTag) { - case JTypeTags.JBYTE: - return "B"; - case JTypeTags.JCHAR: - return "C"; - case JTypeTags.JSHORT: - return "S"; - case JTypeTags.JINT: - return "I"; - case JTypeTags.JLONG: - return "J"; - case JTypeTags.JFLOAT: - return "F"; - case JTypeTags.JDOUBLE: - return "D"; - case JTypeTags.JBOOLEAN: - return "Z"; - default: - throw new BLangCompilerException("invalid element type: " + jType); - } + return switch (jType.jTag) { + case JTypeTags.JBYTE -> "B"; + case JTypeTags.JCHAR -> "C"; + case JTypeTags.JSHORT -> "S"; + case JTypeTags.JINT -> "I"; + case JTypeTags.JLONG -> "J"; + case JTypeTags.JFLOAT -> "F"; + case JTypeTags.JDOUBLE -> "D"; + case JTypeTags.JBOOLEAN -> "Z"; + default -> throw new BLangCompilerException("invalid element type: " + jType); + }; } public static String getSignatureForJType(JType jType) { @@ -507,34 +509,24 @@ public static String getSignatureForJType(JType jType) { return ((JType.JRefType) jType).typeValue; } else if (jType.jTag == JTypeTags.JARRAY) { //must be JArrayType JType eType = ((JType.JArrayType) jType).elementType; - String sig = "["; + StringBuilder sig = new StringBuilder("["); while (eType.jTag == JTypeTags.JARRAY) { eType = ((JType.JArrayType) eType).elementType; - sig += "["; + sig.append("["); } - switch (eType.jTag) { - case JTypeTags.JREF: - return sig + "L" + getSignatureForJType(eType) + ";"; - case JTypeTags.JBYTE: - return sig + "B"; - case JTypeTags.JCHAR: - return sig + "C"; - case JTypeTags.JSHORT: - return sig + "S"; - case JTypeTags.JINT: - return sig + "I"; - case JTypeTags.JLONG: - return sig + "J"; - case JTypeTags.JFLOAT: - return sig + "F"; - case JTypeTags.JDOUBLE: - return sig + "D"; - case JTypeTags.JBOOLEAN: - return sig + "Z"; - default: - throw new BLangCompilerException("invalid element type: " + eType); - } + return switch (eType.jTag) { + case JTypeTags.JREF -> sig + "L" + getSignatureForJType(eType) + ";"; + case JTypeTags.JBYTE -> sig + "B"; + case JTypeTags.JCHAR -> sig + "C"; + case JTypeTags.JSHORT -> sig + "S"; + case JTypeTags.JINT -> sig + "I"; + case JTypeTags.JLONG -> sig + "J"; + case JTypeTags.JFLOAT -> sig + "F"; + case JTypeTags.JDOUBLE -> sig + "D"; + case JTypeTags.JBOOLEAN -> sig + "Z"; + default -> throw new BLangCompilerException("invalid element type: " + eType); + }; } else { throw new BLangCompilerException("invalid element type: " + jType); } @@ -595,24 +587,16 @@ public static void genVarArg(MethodVisitor mv, BIRVarToJVMIndexMap indexMap, BTy GET_BSTRING_FOR_ARRAY_INDEX, true); } else { switch (elementTypeTag) { - case TypeTags.BOOLEAN: - mv.visitMethodInsn(INVOKEINTERFACE, ARRAY_VALUE, "getBoolean", "(J)Z", true); - break; - case TypeTags.BYTE: - mv.visitMethodInsn(INVOKEINTERFACE, ARRAY_VALUE, "getByte", "(J)B", true); - break; - case TypeTags.FLOAT: - mv.visitMethodInsn(INVOKEINTERFACE, ARRAY_VALUE, "getFloat", "(J)D", true); - break; - case TypeTags.HANDLE: + case TypeTags.BOOLEAN -> mv.visitMethodInsn(INVOKEINTERFACE, ARRAY_VALUE, "getBoolean", "(J)Z", true); + case TypeTags.BYTE -> mv.visitMethodInsn(INVOKEINTERFACE, ARRAY_VALUE, "getByte", "(J)B", true); + case TypeTags.FLOAT -> mv.visitMethodInsn(INVOKEINTERFACE, ARRAY_VALUE, "getFloat", "(J)D", true); + case TypeTags.HANDLE -> { mv.visitMethodInsn(INVOKEINTERFACE, ARRAY_VALUE, "getRefValue", GET_STRING_FROM_ARRAY, true); mv.visitTypeInsn(CHECKCAST, HANDLE_VALUE); - break; - default: - mv.visitMethodInsn(INVOKEINTERFACE, ARRAY_VALUE, "getRefValue", GET_STRING_FROM_ARRAY, - true); - break; + } + default -> mv.visitMethodInsn(INVOKEINTERFACE, ARRAY_VALUE, "getRefValue", GET_STRING_FROM_ARRAY, + true); } } @@ -632,34 +616,16 @@ public static void genVarArg(MethodVisitor mv, BIRVarToJVMIndexMap indexMap, BTy private static void genArrayStore(MethodVisitor mv, JType jType) { - int code; - switch (jType.jTag) { - case JTypeTags.JINT: - code = IASTORE; - break; - case JTypeTags.JLONG: - code = LASTORE; - break; - case JTypeTags.JDOUBLE: - code = DASTORE; - break; - case JTypeTags.JBYTE: - case JTypeTags.JBOOLEAN: - code = BASTORE; - break; - case JTypeTags.JSHORT: - code = SASTORE; - break; - case JTypeTags.JCHAR: - code = CASTORE; - break; - case JTypeTags.JFLOAT: - code = FASTORE; - break; - default: - code = AASTORE; - break; - } + int code = switch (jType.jTag) { + case JTypeTags.JINT -> IASTORE; + case JTypeTags.JLONG -> LASTORE; + case JTypeTags.JDOUBLE -> DASTORE; + case JTypeTags.JBYTE, JTypeTags.JBOOLEAN -> BASTORE; + case JTypeTags.JSHORT -> SASTORE; + case JTypeTags.JCHAR -> CASTORE; + case JTypeTags.JFLOAT -> FASTORE; + default -> AASTORE; + }; mv.visitInsn(code); } @@ -667,34 +633,15 @@ private static void genArrayStore(MethodVisitor mv, JType jType) { private static void genArrayNew(MethodVisitor mv, JType elementType) { switch (elementType.jTag) { - case JTypeTags.JINT: - mv.visitIntInsn(NEWARRAY, T_INT); - break; - case JTypeTags.JLONG: - mv.visitIntInsn(NEWARRAY, T_LONG); - break; - case JTypeTags.JDOUBLE: - mv.visitIntInsn(NEWARRAY, T_DOUBLE); - break; - case JTypeTags.JBYTE: - case JTypeTags.JBOOLEAN: - mv.visitIntInsn(NEWARRAY, T_BOOLEAN); - break; - case JTypeTags.JSHORT: - mv.visitIntInsn(NEWARRAY, T_SHORT); - break; - case JTypeTags.JCHAR: - mv.visitIntInsn(NEWARRAY, T_CHAR); - break; - case JTypeTags.JFLOAT: - mv.visitIntInsn(NEWARRAY, T_FLOAT); - break; - case JTypeTags.JREF: - case JTypeTags.JARRAY: - mv.visitTypeInsn(ANEWARRAY, getSignatureForJType(elementType)); - break; - default: - throw new BLangCompilerException("invalid type for var-arg: " + elementType); + case JTypeTags.JINT -> mv.visitIntInsn(NEWARRAY, T_INT); + case JTypeTags.JLONG -> mv.visitIntInsn(NEWARRAY, T_LONG); + case JTypeTags.JDOUBLE -> mv.visitIntInsn(NEWARRAY, T_DOUBLE); + case JTypeTags.JBYTE, JTypeTags.JBOOLEAN -> mv.visitIntInsn(NEWARRAY, T_BOOLEAN); + case JTypeTags.JSHORT -> mv.visitIntInsn(NEWARRAY, T_SHORT); + case JTypeTags.JCHAR -> mv.visitIntInsn(NEWARRAY, T_CHAR); + case JTypeTags.JFLOAT -> mv.visitIntInsn(NEWARRAY, T_FLOAT); + case JTypeTags.JREF, JTypeTags.JARRAY -> mv.visitTypeInsn(ANEWARRAY, getSignatureForJType(elementType)); + default -> throw new BLangCompilerException("invalid type for var-arg: " + elementType); } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/InteropValidationRequest.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/InteropValidationRequest.java index b9e7203d2b0f..c366098ca248 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/InteropValidationRequest.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/InteropValidationRequest.java @@ -17,6 +17,8 @@ */ package org.wso2.ballerinalang.compiler.bir.codegen.interop; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JMethodKind; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JType; import org.wso2.ballerinalang.compiler.semantics.model.types.BInvokableType; import org.wso2.ballerinalang.compiler.semantics.model.types.BType; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/InteropValidator.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/InteropValidator.java index 409d83bf4a0b..ccee37a09242 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/InteropValidator.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/InteropValidator.java @@ -22,6 +22,11 @@ import io.ballerina.projects.PlatformLibrary; import io.ballerina.projects.PlatformLibraryScope; import org.ballerinalang.util.diagnostic.DiagnosticErrorCode; +import org.wso2.ballerinalang.compiler.bir.codegen.exceptions.JInteropException; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JFieldBIRFunction; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JMethod; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JMethodBIRFunction; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JavaField; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; import org.wso2.ballerinalang.compiler.diagnostic.BLangDiagnosticLog; import org.wso2.ballerinalang.compiler.semantics.model.SymbolTable; @@ -176,7 +181,7 @@ private void validateTypeAttachedFunctions(BIRNode.BIRPackage module, ClassLoade } private ClassLoader makeClassLoader(Set moduleDependencies) { - if (moduleDependencies == null || moduleDependencies.size() == 0) { + if (moduleDependencies == null || moduleDependencies.isEmpty()) { return Thread.currentThread().getContextClassLoader(); } List dependentJars = new ArrayList<>(); @@ -220,9 +225,7 @@ private BIRNode.BIRFunction getBirFunction(BIRNode.BIRFunction birFunc, ClassLoa BIRNode.BIRFunction createJInteropFunction(InteropValidationRequest jInteropValidationReq, BIRNode.BIRFunction birFunc, ClassLoader classLoader) { - if (jInteropValidationReq instanceof InteropValidationRequest.MethodValidationRequest) { - InteropValidationRequest.MethodValidationRequest methodValidationRequest = - ((InteropValidationRequest.MethodValidationRequest) jInteropValidationReq); + if (jInteropValidationReq instanceof InteropValidationRequest.MethodValidationRequest methodValidationRequest) { methodValidationRequest.restParamExist = birFunc.restParam != null; JMethod jMethod = validateAndGetJMethod(methodValidationRequest, classLoader); return new JMethodBIRFunction(birFunc, jMethod); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JFieldMethod.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JFieldMethod.java index 4961ca2804de..c6e00584fa92 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JFieldMethod.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JFieldMethod.java @@ -22,18 +22,18 @@ * * @since 1.2.0 */ -enum JFieldMethod { +public enum JFieldMethod { ACCESS("access"), MUTATE("mutate"); - private String strValue; + private final String strValue; JFieldMethod(String strValue) { this.strValue = strValue; } - static JFieldMethod getKind(String value) { + public static JFieldMethod getKind(String value) { if ("access".equals(value)) { return ACCESS; @@ -41,7 +41,7 @@ static JFieldMethod getKind(String value) { return MUTATE; } - String getStringValue() { + public String getStringValue() { return this.strValue; } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JInterop.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JInterop.java index 83019e528210..fdd34827b364 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JInterop.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JInterop.java @@ -18,29 +18,32 @@ package org.wso2.ballerinalang.compiler.bir.codegen.interop; import org.ballerinalang.util.diagnostic.DiagnosticErrorCode; +import org.wso2.ballerinalang.compiler.bir.codegen.exceptions.JInteropException; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JMethodKind; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JType; import java.util.ArrayList; import java.util.List; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JType.getJTypeForPrimitive; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JARRAY; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JBOOLEAN; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JBYTE; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JCHAR; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JDOUBLE; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JFLOAT; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JINT; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JLONG; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JNO; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JREF; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JSHORT; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JType.getJTypeForPrimitive; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JARRAY; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JBOOLEAN; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JBYTE; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JCHAR; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JDOUBLE; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JFLOAT; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JINT; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JLONG; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JNO; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JREF; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JSHORT; /** * This class contains a set of utility methods and constants used in this implementation. * * @since 1.2.0 */ -class JInterop { +final class JInterop { static final String INTEROP_ANNOT_ORG = "ballerina"; static final String INTEROP_ANNOT_MODULE = "jballerina.java"; @@ -85,52 +88,6 @@ static JType getJType(Class jTypeClass) { return jRefType; } - static String getMethodSig(Class returnType, Class... parameterTypes) { - - StringBuilder sb = new StringBuilder(); - sb.append('('); - for (Class type : parameterTypes) { - sb.append(getSig(type)); - } - sb.append(')'); - return sb.append(getSig(returnType)).toString(); - } - - static String getSig(Class c) { - - if (c.isPrimitive()) { - if (int.class == c) { - return "I"; - } else if (long.class == c) { - return "J"; - } else if (boolean.class == c) { - return "Z"; - } else if (byte.class == c) { - return "B"; - } else if (short.class == c) { - return "S"; - } else if (char.class == c) { - return "C"; - } else if (float.class == c) { - return "F"; - } else if (double.class == c) { - return "D"; - } else { - // This is void - return "V"; - } - } else if (void.class == c || Void.class == c) { - return "V"; - } else { - String className = c.getName().replace('.', '/'); - if (c.isArray()) { - return className; - } else { - return 'L' + className + ';'; - } - } - } - static ParamTypeConstraint[] buildParamTypeConstraints(List javaTypeConstraints, ClassLoader classLoader) { if (javaTypeConstraints == null) { @@ -148,16 +105,12 @@ static ParamTypeConstraint[] buildParamTypeConstraints(List javaTypeConst private static ParamTypeConstraint buildParamTypeConstraint(JType javaTypeConstraint, ClassLoader classLoader) { - switch (javaTypeConstraint.jTag) { - case JREF: - return buildConstraintFromJavaRefType((JType.JRefType) javaTypeConstraint, classLoader); - case JARRAY: - return buildConstraintFromJavaArrayType((JType.JArrayType) javaTypeConstraint, classLoader); - case JNO: - return ParamTypeConstraint.NO_CONSTRAINT; - default: - return buildConstraintFromJavaPrimitiveType(javaTypeConstraint); - } + return switch (javaTypeConstraint.jTag) { + case JREF -> buildConstraintFromJavaRefType((JType.JRefType) javaTypeConstraint, classLoader); + case JARRAY -> buildConstraintFromJavaArrayType((JType.JArrayType) javaTypeConstraint, classLoader); + case JNO -> ParamTypeConstraint.NO_CONSTRAINT; + default -> buildConstraintFromJavaPrimitiveType(javaTypeConstraint); + }; } private static ParamTypeConstraint buildConstraintFromJavaRefType(JType.JRefType javaRefType, @@ -192,62 +145,35 @@ private static String getJavaArrayTypeSig(JType.JArrayType jArrayType) { private static ParamTypeConstraint buildConstraintFromJavaPrimitiveType(JType primitiveTypeName) { // Java primitive types: byte, short, char, int, long, float, double, boolean - Class constraintClass; - switch (primitiveTypeName.jTag) { - case JBYTE: - constraintClass = byte.class; - break; - case JSHORT: - constraintClass = short.class; - break; - case JCHAR: - constraintClass = char.class; - break; - case JINT: - constraintClass = int.class; - break; - case JLONG: - constraintClass = long.class; - break; - case JFLOAT: - constraintClass = float.class; - break; - case JDOUBLE: - constraintClass = double.class; - break; - case JBOOLEAN: - constraintClass = boolean.class; - break; - default: - throw new JInteropException(DiagnosticErrorCode.UNSUPPORTED_PRIMITIVE_TYPE, - "Unsupported Java primitive type '" + primitiveTypeName + "'"); - } + Class constraintClass = switch (primitiveTypeName.jTag) { + case JBYTE -> byte.class; + case JSHORT -> short.class; + case JCHAR -> char.class; + case JINT -> int.class; + case JLONG -> long.class; + case JFLOAT -> float.class; + case JDOUBLE -> double.class; + case JBOOLEAN -> boolean.class; + default -> throw new JInteropException(DiagnosticErrorCode.UNSUPPORTED_PRIMITIVE_TYPE, + "Unsupported Java primitive type '" + primitiveTypeName + "'"); + }; return new ParamTypeConstraint(constraintClass); } private static String getSignatureFromJavaPrimitiveType(JType primitiveTypeName) { // Java primitive types: byte, short, char, int, long, float, double, boolean - switch (primitiveTypeName.jTag) { - case JBYTE: - return "B"; - case JSHORT: - return "S"; - case JCHAR: - return "C"; - case JINT: - return "I"; - case JLONG: - return "J"; - case JFLOAT: - return "F"; - case JDOUBLE: - return "D"; - case JBOOLEAN: - return "Z"; - default: - throw new JInteropException(DiagnosticErrorCode.UNSUPPORTED_PRIMITIVE_TYPE, - "Unsupported Java primitive type '" + primitiveTypeName + "'"); - } + return switch (primitiveTypeName.jTag) { + case JBYTE -> "B"; + case JSHORT -> "S"; + case JCHAR -> "C"; + case JINT -> "I"; + case JLONG -> "J"; + case JFLOAT -> "F"; + case JDOUBLE -> "D"; + case JBOOLEAN -> "Z"; + default -> throw new JInteropException(DiagnosticErrorCode.UNSUPPORTED_PRIMITIVE_TYPE, + "Unsupported Java primitive type '" + primitiveTypeName + "'"); + }; } static Class loadClass(String className, ClassLoader classLoader) { @@ -279,15 +205,10 @@ static JFieldMethod getFieldMethodFromAnnotTag(String annotTagRef) { static boolean isInteropAnnotationTag(String annotTag) { - switch (annotTag) { - case CONSTRUCTOR_ANNOT_TAG: - case METHOD_ANNOT_TAG: - case FIELD_GET_ANNOT_TAG: - case FIELD_PUT_ANNOT_TAG: - return true; - default: - return false; - } + return switch (annotTag) { + case CONSTRUCTOR_ANNOT_TAG, METHOD_ANNOT_TAG, FIELD_GET_ANNOT_TAG, FIELD_PUT_ANNOT_TAG -> true; + default -> false; + }; } static boolean isMethodAnnotationTag(String annotTag) { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethodRequest.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethodRequest.java index 62b4447798c5..dfa5278a93e8 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethodRequest.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethodRequest.java @@ -18,6 +18,7 @@ package org.wso2.ballerinalang.compiler.bir.codegen.interop; import org.ballerinalang.model.symbols.SymbolKind; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JMethodKind; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BInvokableTypeSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BVarSymbol; import org.wso2.ballerinalang.compiler.semantics.model.types.BInvokableType; @@ -52,7 +53,7 @@ class JMethodRequest { boolean restParamExist = false; BType receiverType = null; - private static Unifier unifier = new Unifier(); + private static final Unifier unifier = new Unifier(); private JMethodRequest() { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethodResolver.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethodResolver.java index 43539b2f6d5b..29c69a942619 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethodResolver.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethodResolver.java @@ -34,8 +34,12 @@ import io.ballerina.runtime.api.values.BXml; import org.ballerinalang.util.diagnostic.DiagnosticErrorCode; import org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil; +import org.wso2.ballerinalang.compiler.bir.codegen.exceptions.JInteropException; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JMethod; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JMethodKind; import org.wso2.ballerinalang.compiler.semantics.model.SymbolTable; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BVarSymbol; +import org.wso2.ballerinalang.compiler.semantics.model.symbols.Symbols; import org.wso2.ballerinalang.compiler.semantics.model.types.BArrayType; import org.wso2.ballerinalang.compiler.semantics.model.types.BFiniteType; import org.wso2.ballerinalang.compiler.semantics.model.types.BType; @@ -43,6 +47,7 @@ import org.wso2.ballerinalang.compiler.semantics.model.types.BUnionType; import org.wso2.ballerinalang.compiler.tree.expressions.BLangExpression; import org.wso2.ballerinalang.compiler.util.TypeTags; +import org.wso2.ballerinalang.util.Flags; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; @@ -194,7 +199,7 @@ private boolean hasEquivalentPathAndFunctionParamCount(JMethodRequest jMethodReq } if (!isParamAssignableToBArray(paramTypes[count - 1]) || !isParamAssignableToBArray(paramTypes[count - 2]) || isFirstPathParamARestParam(jMethodRequest, jMethod) - || isFirstFunctionParamARestParam(jMethodRequest, jMethod)) { + || isFunctionParamARestParam(jMethodRequest, jMethod)) { return false; } if (count == 3) { @@ -238,23 +243,21 @@ private boolean hasEquivalentPathParamCount(JMethodRequest jMethodRequest, JMeth } private boolean hasEquivalentFunctionParamCount(JMethodRequest jMethodRequest, JMethod jMethod) { - // Currently, this is only applicable for resource and remote methods which have empty path parameters. - // If path parameters are present, this will be handled by 'hasEquivalentPathAndFunctionParamCount' method - // by bundling both. - if (jMethodRequest.receiverType == null || jMethodRequest.pathParamCount != 0 - || jMethodRequest.bParamTypes.length == 0) { - return false; - } + // This is only applicable for resource and remote methods which have at least one function + // parameter other than path parameters and the bundling of path parameters is not required. Class[] paramTypes = jMethod.getParamTypes(); - boolean isFirstParamServiceObject = jMethodRequest.bParamTypes[0].tag == TypeTags.SERVICE; - // Get the count of parameters of the resource/remote methods by excluding the receiver type. - int count = isFirstParamServiceObject ? paramTypes.length - 1 : paramTypes.length; - int reducedParamCount = isFirstParamServiceObject ? 2 : 1; - if (count < reducedParamCount || count > reducedParamCount + 2) { + int count = paramTypes.length; + int reducedParamCount = jMethodRequest.pathParamCount + 1; + int functionParamCount = getBFuncParamCount(jMethodRequest, jMethod) - jMethodRequest.pathParamCount; + // TODO: Remove 'Symbols.isFlagOn(jMethodRequest.bParamTypes[0].flags, Flags.SERVICE)' check after fixing + // https://github.com/ballerina-platform/ballerina-lang/issues/42456. + if (jMethodRequest.receiverType == null || functionParamCount < 1 + || count < reducedParamCount || count > reducedParamCount + 2 + || Symbols.isFlagOn(jMethodRequest.bParamTypes[0].flags, Flags.SERVICE)) { return false; } if (!isParamAssignableToBArray(paramTypes[count - 1]) - || isFirstFunctionParamARestParam(jMethodRequest, jMethod)) { + || isFunctionParamARestParam(jMethodRequest, jMethod)) { return false; } if (count == reducedParamCount) { @@ -263,10 +266,12 @@ private boolean hasEquivalentFunctionParamCount(JMethodRequest jMethodRequest, J // This is for object interop functions when self is passed as a parameter jMethod.setReceiverType(jMethodRequest.receiverType); return true; + } else if (count == (reducedParamCount + 2)) { + // This is for object interop functions when both BalEnv and self is passed as parameters. + jMethod.setReceiverType(jMethodRequest.receiverType); + return jMethod.isBalEnvAcceptingMethod(); } - // This is for object interop functions when both BalEnv and self is passed as parameters. - jMethod.setReceiverType(jMethodRequest.receiverType); - return jMethod.isBalEnvAcceptingMethod(); + return false; } private boolean isParamAssignableToBArray(Class paramType) { @@ -445,7 +450,7 @@ private void validateArgumentTypes(JMethodRequest jMethodRequest, JMethod jMetho jParamType = jParamTypes[0]; } BType bParamType = jMethod.getReceiverType(); - if (!isValidParamBType(jParamType, bParamType, false, jMethodRequest.restParamExist)) { + if (isInvalidParamBType(jParamType, bParamType, false, jMethodRequest.restParamExist)) { throwNoSuchMethodError(jMethodRequest.methodName, jParamType, bParamType, jMethodRequest.declaringClass); } @@ -488,7 +493,7 @@ private void validateArgumentTypes(JMethodRequest jMethodRequest, JMethod jMetho BType bParamType = bParamTypes[i]; Class jParamType = jParamTypes[k]; boolean isLastPram = jParamTypes.length == k + 1; - if (!isValidParamBType(jParamType, bParamType, isLastPram, jMethodRequest.restParamExist)) { + if (isInvalidParamBType(jParamType, bParamType, isLastPram, jMethodRequest.restParamExist)) { throwNoSuchMethodError(jMethodRequest.methodName, jParamType, bParamType, jMethodRequest.declaringClass); } @@ -551,120 +556,120 @@ private void validateReturnTypes(JMethodRequest jMethodRequest, JMethod jMethod) } } - private boolean isValidParamBType(Class jType, BType bType, boolean isLastParam, boolean restParamExist) { + private boolean isInvalidParamBType(Class jType, BType bType, boolean isLastParam, boolean restParamExist) { bType = JvmCodeGenUtil.getImpliedType(bType); try { String jTypeName = jType.getTypeName(); switch (bType.tag) { - case TypeTags.ANY: - case TypeTags.ANYDATA: + case TypeTags.ANY, TypeTags.ANYDATA -> { if (jTypeName.equals(J_STRING_TNAME)) { - return false; + return true; } - return !jType.isPrimitive(); - case TypeTags.HANDLE: - return !jType.isPrimitive(); - case TypeTags.NIL: - return jTypeName.equals(J_VOID_TNAME); - case TypeTags.INT: - case TypeTags.SIGNED32_INT: - case TypeTags.SIGNED16_INT: - case TypeTags.SIGNED8_INT: - case TypeTags.UNSIGNED32_INT: - case TypeTags.UNSIGNED16_INT: - case TypeTags.UNSIGNED8_INT: - case TypeTags.BYTE: - case TypeTags.FLOAT: + return jType.isPrimitive(); + } + case TypeTags.HANDLE -> { + return jType.isPrimitive(); + } + case TypeTags.NIL -> { + return !jTypeName.equals(J_VOID_TNAME); + } + case TypeTags.INT, TypeTags.SIGNED32_INT, TypeTags.SIGNED16_INT, TypeTags.SIGNED8_INT, + TypeTags.UNSIGNED32_INT, TypeTags.UNSIGNED16_INT, TypeTags.UNSIGNED8_INT, TypeTags.BYTE, + TypeTags.FLOAT -> { if (jTypeName.equals(J_OBJECT_TNAME)) { - return true; + return false; } - if (TypeTags.isIntegerTypeTag(bType.tag) && jTypeName.equals(J_LONG_OBJ_TNAME)) { - return true; + return false; } - if (bType.tag == TypeTags.BYTE && jTypeName.equals(J_INTEGER_OBJ_TNAME)) { - return true; + return false; } - if (bType.tag == TypeTags.FLOAT && jTypeName.equals(J_DOUBLE_OBJ_TNAME)) { - return true; + return false; } - - return jType.isPrimitive() && (jTypeName.equals(J_PRIMITIVE_INT_TNAME) || - jTypeName.equals(J_PRIMITIVE_BYTE_TNAME) || jTypeName.equals(J_PRIMITIVE_SHORT_TNAME) || - jTypeName.equals(J_PRIMITIVE_LONG_TNAME) || jTypeName.equals(J_PRIMITIVE_CHAR_TNAME) || - jTypeName.equals(J_PRIMITIVE_FLOAT_TNAME) || jTypeName.equals(J_PRIMITIVE_DOUBLE_TNAME)); - case TypeTags.BOOLEAN: + return !jType.isPrimitive() || (!jTypeName.equals(J_PRIMITIVE_INT_TNAME) && + !jTypeName.equals(J_PRIMITIVE_BYTE_TNAME) && !jTypeName.equals(J_PRIMITIVE_SHORT_TNAME) && + !jTypeName.equals(J_PRIMITIVE_LONG_TNAME) && !jTypeName.equals(J_PRIMITIVE_CHAR_TNAME) && + !jTypeName.equals(J_PRIMITIVE_FLOAT_TNAME) && !jTypeName.equals(J_PRIMITIVE_DOUBLE_TNAME)); + } + case TypeTags.BOOLEAN -> { if (jTypeName.equals(J_OBJECT_TNAME) || jTypeName.equals(J_BOOLEAN_OBJ_TNAME)) { - return true; + return false; } - return jType.isPrimitive() && jTypeName.equals(J_PRIMITIVE_BOOLEAN_TNAME); - case TypeTags.DECIMAL: - return this.classLoader.loadClass(BDecimal.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.STRING: - case TypeTags.CHAR_STRING: - return this.classLoader.loadClass(BString.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.MAP: - case TypeTags.RECORD: - return this.classLoader.loadClass(BMap.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.JSON: - case TypeTags.READONLY: - return jTypeName.equals(J_OBJECT_TNAME); - case TypeTags.OBJECT: - return this.classLoader.loadClass(BObject.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.ERROR: - return this.classLoader.loadClass(BError.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.XML: - case TypeTags.XML_ELEMENT: - case TypeTags.XML_PI: - case TypeTags.XML_COMMENT: - case TypeTags.XML_TEXT: - return this.classLoader.loadClass(BXml.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.TUPLE: - case TypeTags.ARRAY: - return isValidListType(jType, isLastParam, restParamExist); - case TypeTags.UNION: + return !jType.isPrimitive() || !jTypeName.equals(J_PRIMITIVE_BOOLEAN_TNAME); + } + case TypeTags.DECIMAL -> { + return !this.classLoader.loadClass(BDecimal.class.getCanonicalName()).isAssignableFrom(jType); + } + case TypeTags.STRING, TypeTags.CHAR_STRING -> { + return !this.classLoader.loadClass(BString.class.getCanonicalName()).isAssignableFrom(jType); + } + case TypeTags.MAP, TypeTags.RECORD -> { + return !this.classLoader.loadClass(BMap.class.getCanonicalName()).isAssignableFrom(jType); + } + case TypeTags.JSON, TypeTags.READONLY -> { + return !jTypeName.equals(J_OBJECT_TNAME); + } + case TypeTags.OBJECT -> { + return !this.classLoader.loadClass(BObject.class.getCanonicalName()).isAssignableFrom(jType); + } + case TypeTags.ERROR -> { + return !this.classLoader.loadClass(BError.class.getCanonicalName()).isAssignableFrom(jType); + } + case TypeTags.XML, TypeTags.XML_ELEMENT, TypeTags.XML_PI, TypeTags.XML_COMMENT, TypeTags.XML_TEXT -> { + return !this.classLoader.loadClass(BXml.class.getCanonicalName()).isAssignableFrom(jType); + } + case TypeTags.TUPLE, TypeTags.ARRAY -> { + return !isValidListType(jType, isLastParam, restParamExist); + } + case TypeTags.UNION -> { if (jTypeName.equals(J_OBJECT_TNAME)) { - return true; + return false; } - Set members = ((BUnionType) bType).getMemberTypes(); // for method arguments, all ballerina member types should be assignable to java-type. for (BType member : members) { - if (!isValidParamBType(jType, member, isLastParam, restParamExist)) { - return false; + if (isInvalidParamBType(jType, member, isLastParam, restParamExist)) { + return true; } } - return true; - case TypeTags.FINITE: + return false; + } + case TypeTags.FINITE -> { if (jTypeName.equals(J_OBJECT_TNAME)) { - return true; + return false; } - Set valueSpace = ((BFiniteType) bType).getValueSpace(); for (BLangExpression value : valueSpace) { - if (!isValidParamBType(jType, value.getBType(), isLastParam, restParamExist)) { - return false; + if (isInvalidParamBType(jType, value.getBType(), isLastParam, restParamExist)) { + return true; } } - return true; - case TypeTags.FUNCTION_POINTER: - case TypeTags.INVOKABLE: - return this.classLoader.loadClass(BFunctionPointer.class - .getCanonicalName()).isAssignableFrom(jType); - case TypeTags.FUTURE: - return this.classLoader.loadClass(BFuture.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.TYPEDESC: - return this.classLoader.loadClass(BTypedesc.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.STREAM: - return this.classLoader.loadClass(BStream.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.TABLE: - return this.classLoader.loadClass(BTable.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.REGEXP: - return this.classLoader.loadClass(BRegexpValue.class.getCanonicalName()).isAssignableFrom(jType); - default: return false; + } + case TypeTags.FUNCTION_POINTER, TypeTags.INVOKABLE -> { + return !this.classLoader.loadClass(BFunctionPointer.class + .getCanonicalName()).isAssignableFrom(jType); + } + case TypeTags.FUTURE -> { + return !this.classLoader.loadClass(BFuture.class.getCanonicalName()).isAssignableFrom(jType); + } + case TypeTags.TYPEDESC -> { + return !this.classLoader.loadClass(BTypedesc.class.getCanonicalName()).isAssignableFrom(jType); + } + case TypeTags.STREAM -> { + return !this.classLoader.loadClass(BStream.class.getCanonicalName()).isAssignableFrom(jType); + } + case TypeTags.TABLE -> { + return !this.classLoader.loadClass(BTable.class.getCanonicalName()).isAssignableFrom(jType); + } + case TypeTags.REGEXP -> { + return !this.classLoader.loadClass(BRegexpValue.class.getCanonicalName()).isAssignableFrom(jType); + } + default -> { + return true; + } } } catch (ClassNotFoundException | NoClassDefFoundError e) { throw new JInteropException(CLASS_NOT_FOUND, e.getMessage(), e); @@ -683,27 +688,23 @@ private boolean isValidReturnBType(Class jType, BType bType, JMethodRequest j try { String jTypeName = jType.getTypeName(); switch (bType.tag) { - case TypeTags.ANY: - case TypeTags.ANYDATA: + case TypeTags.ANY, TypeTags.ANYDATA -> { if (jTypeName.equals(J_STRING_TNAME)) { return false; } return !jType.isPrimitive(); - case TypeTags.HANDLE: + } + case TypeTags.HANDLE -> { return !jType.isPrimitive(); - case TypeTags.NIL: + } + case TypeTags.NIL -> { return jTypeName.equals(J_VOID_TNAME); - case TypeTags.INT: - case TypeTags.SIGNED32_INT: - case TypeTags.SIGNED16_INT: - case TypeTags.SIGNED8_INT: - case TypeTags.UNSIGNED32_INT: - case TypeTags.UNSIGNED16_INT: - case TypeTags.UNSIGNED8_INT: + } + case TypeTags.INT, TypeTags.SIGNED32_INT, TypeTags.SIGNED16_INT, TypeTags.SIGNED8_INT, + TypeTags.UNSIGNED32_INT, TypeTags.UNSIGNED16_INT, TypeTags.UNSIGNED8_INT -> { if (jTypeName.equals(J_OBJECT_TNAME)) { return true; } - if (jType.isPrimitive()) { return (jTypeName.equals(J_PRIMITIVE_INT_TNAME) || jTypeName.equals(J_PRIMITIVE_BYTE_TNAME) || jTypeName.equals(J_PRIMITIVE_SHORT_TNAME) || jTypeName.equals(J_PRIMITIVE_LONG_TNAME) || @@ -711,21 +712,21 @@ private boolean isValidReturnBType(Class jType, BType bType, JMethodRequest j } else { return jTypeName.equals(J_LONG_OBJ_TNAME); } - case TypeTags.BYTE: + } + case TypeTags.BYTE -> { if (jTypeName.equals(J_OBJECT_TNAME)) { return true; } - if (jType.isPrimitive()) { return jTypeName.equals(J_PRIMITIVE_BYTE_TNAME); } else { return jTypeName.equals(J_INTEGER_OBJ_TNAME); } - case TypeTags.FLOAT: + } + case TypeTags.FLOAT -> { if (jTypeName.equals(J_OBJECT_TNAME)) { return true; } - if (jType.isPrimitive()) { return (jTypeName.equals(J_PRIMITIVE_INT_TNAME) || jTypeName.equals(J_PRIMITIVE_BYTE_TNAME) || jTypeName.equals(J_PRIMITIVE_SHORT_TNAME) || jTypeName.equals(J_PRIMITIVE_LONG_TNAME) || @@ -734,51 +735,50 @@ private boolean isValidReturnBType(Class jType, BType bType, JMethodRequest j } else { return jTypeName.equals(J_DOUBLE_OBJ_TNAME); } - case TypeTags.BOOLEAN: + } + case TypeTags.BOOLEAN -> { if (jTypeName.equals(J_OBJECT_TNAME) || jTypeName.equals(J_BOOLEAN_OBJ_TNAME)) { return true; } return jType.isPrimitive() && jTypeName.equals(J_PRIMITIVE_BOOLEAN_TNAME); - case TypeTags.DECIMAL: + } + case TypeTags.DECIMAL -> { return this.classLoader.loadClass(BDecimal.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.STRING: - case TypeTags.CHAR_STRING: + } + case TypeTags.STRING, TypeTags.CHAR_STRING -> { return this.classLoader.loadClass(BString.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.MAP: - case TypeTags.RECORD: + } + case TypeTags.MAP, TypeTags.RECORD -> { return this.classLoader.loadClass(BMap.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.JSON: + } + case TypeTags.JSON -> { if (jTypeName.equals(J_OBJECT_TNAME)) { return true; } - if (!visitedSet.add(jType)) { return true; } - return isValidReturnBType(jType, symbolTable.jsonType, jMethodRequest, visitedSet); - case TypeTags.OBJECT: + } + case TypeTags.OBJECT -> { return this.classLoader.loadClass(BObject.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.ERROR: + } + case TypeTags.ERROR -> { return this.classLoader.loadClass(BError.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.XML: - case TypeTags.XML_ELEMENT: - case TypeTags.XML_PI: - case TypeTags.XML_COMMENT: - case TypeTags.XML_TEXT: + } + case TypeTags.XML, TypeTags.XML_ELEMENT, TypeTags.XML_PI, TypeTags.XML_COMMENT, TypeTags.XML_TEXT -> { return this.classLoader.loadClass(BXml.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.TUPLE: - case TypeTags.ARRAY: + } + case TypeTags.TUPLE, TypeTags.ARRAY -> { return isValidListType(jType, true, jMethodRequest.restParamExist); - case TypeTags.UNION: + } + case TypeTags.UNION -> { if (jTypeName.equals(J_OBJECT_TNAME)) { return true; } - if (!visitedSet.add(jType)) { return true; } - Set members = ((BUnionType) bType).getMemberTypes(); // for method return, java-type should be matched to at-least one of the ballerina member types. for (BType member : members) { @@ -787,13 +787,14 @@ private boolean isValidReturnBType(Class jType, BType bType, JMethodRequest j } } return false; - case TypeTags.READONLY: + } + case TypeTags.READONLY -> { return isReadOnlyCompatibleReturnType(jType, jMethodRequest); - case TypeTags.FINITE: + } + case TypeTags.FINITE -> { if (jTypeName.equals(J_OBJECT_TNAME)) { return true; } - Set valueSpace = ((BFiniteType) bType).getValueSpace(); for (BLangExpression value : valueSpace) { if (isValidReturnBType(jType, value.getBType(), jMethodRequest, visitedSet)) { @@ -801,20 +802,26 @@ private boolean isValidReturnBType(Class jType, BType bType, JMethodRequest j } } return false; - case TypeTags.FUNCTION_POINTER: - case TypeTags.INVOKABLE: + } + case TypeTags.FUNCTION_POINTER, TypeTags.INVOKABLE -> { return this.classLoader.loadClass(BFunctionPointer.class.getCanonicalName()) .isAssignableFrom(jType); - case TypeTags.FUTURE: + } + case TypeTags.FUTURE -> { return this.classLoader.loadClass(BFuture.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.TYPEDESC: + } + case TypeTags.TYPEDESC -> { return this.classLoader.loadClass(BTypedesc.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.STREAM: + } + case TypeTags.STREAM -> { return this.classLoader.loadClass(BStream.class.getCanonicalName()).isAssignableFrom(jType); - case TypeTags.TABLE: + } + case TypeTags.TABLE -> { return this.classLoader.loadClass(BTable.class.getCanonicalName()).isAssignableFrom(jType); - default: + } + default -> { return false; + } } } catch (ClassNotFoundException | NoClassDefFoundError e) { throw new JInteropException(CLASS_NOT_FOUND, e.getMessage(), e); @@ -1045,10 +1052,11 @@ private boolean isFirstPathParamARestParam(JMethodRequest jMethodRequest, JMetho jMethodRequest.bParamTypes[0].tag == TypeTags.HANDLE; } - private boolean isFirstFunctionParamARestParam(JMethodRequest jMethodRequest, JMethod jMethod) { - return jMethod.isStatic() ? jMethodRequest.bParamTypes[jMethodRequest.pathParamCount].tag == TypeTags.ARRAY : + private boolean isFunctionParamARestParam(JMethodRequest jMethodRequest, JMethod jMethod) { + int funcParamCount = getBFuncParamCount(jMethodRequest, jMethod) - jMethodRequest.pathParamCount; + return (jMethod.isStatic() ? jMethodRequest.bParamTypes[jMethodRequest.pathParamCount].tag == TypeTags.ARRAY : jMethodRequest.bParamTypes[jMethodRequest.pathParamCount + 1].tag == TypeTags.ARRAY && - jMethodRequest.bParamTypes[0].tag == TypeTags.HANDLE; + jMethodRequest.bParamTypes[0].tag == TypeTags.HANDLE) && funcParamCount == 1; } private String getParamTypesAsString(ParamTypeConstraint[] constraints) { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JType.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JType.java deleted file mode 100644 index 242664184efe..000000000000 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JType.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. - * - * WSO2 Inc. 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 org.wso2.ballerinalang.compiler.bir.codegen.interop; - -import org.wso2.ballerinalang.compiler.semantics.model.types.BType; - -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.OBJECT; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JARRAY; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JBOOLEAN; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JBYTE; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JCHAR; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JDOUBLE; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JFLOAT; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JINT; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JLONG; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JREF; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JSHORT; -import static org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags.JVOID; -import static org.wso2.ballerinalang.compiler.util.TypeTags.BOOLEAN; -import static org.wso2.ballerinalang.compiler.util.TypeTags.BYTE; -import static org.wso2.ballerinalang.compiler.util.TypeTags.FLOAT; -import static org.wso2.ballerinalang.compiler.util.TypeTags.INT; - -/** - * Interop representation of Java types. - * - * @since 1.2.0 - */ -public class JType extends BType { - - private static final String JBYTE_KIND = "byte"; - private static final String JCHAR_KIND = "char"; - private static final String JSHORT_KIND = "short"; - private static final String JINT_KIND = "int"; - private static final String JLONG_KIND = "long"; - private static final String JFLOAT_KIND = "float"; - private static final String JDOUBLE_KIND = "double"; - private static final String JBOOLEAN_KIND = "boolean"; - private static final String JVOID_KIND = "void"; - private static final String JARRAY_KIND = "array"; - private static final String JREF_KIND = "ref"; - private static final String JNO_KIND = "no"; - static JType jVoid = new JType(JVOID); - private static JType jByte = new JType(JBYTE); - private static JType jChar = new JType(JCHAR); - private static JType jShort = new JType(JSHORT); - private static JType jInt = new JType(JINT); - private static JType jLong = new JType(JLONG); - private static JType jFloat = new JType(JFLOAT); - private static JType jDouble = new JType(JDOUBLE); - private static JType jBoolean = new JType(JBOOLEAN); - public int jTag; - - JType(int jTag) { - - super(JTypeTags.JTYPE, null); - this.jTag = jTag; - } - - static JType getJTypeFromTypeName(String typeName) { - - switch (typeName) { - case JBYTE_KIND: - return jByte; - case JCHAR_KIND: - return jChar; - case JSHORT_KIND: - return jShort; - case JINT_KIND: - return jInt; - case JLONG_KIND: - return jLong; - case JFLOAT_KIND: - return jFloat; - case JDOUBLE_KIND: - return jDouble; - case JBOOLEAN_KIND: - return jBoolean; - case JVOID_KIND: - return jVoid; - default: - return new JRefType(typeName.replace('.', '/')); - } - } - - static JType getJTypeForPrimitive(String typeName) { - - switch (typeName) { - case JBYTE_KIND: - return jByte; - case JCHAR_KIND: - return jChar; - case JSHORT_KIND: - return jShort; - case JINT_KIND: - return jInt; - case JLONG_KIND: - return jLong; - case JFLOAT_KIND: - return jFloat; - case JDOUBLE_KIND: - return jDouble; - case JBOOLEAN_KIND: - return jBoolean; - case JVOID_KIND: - return jVoid; - default: - throw new IllegalArgumentException("The Java " + typeName + " type is not yet supported."); - } - } - - static int getJTypeTagForPrimitive(String typeName) { - - switch (typeName) { - case JBYTE_KIND: - return JBYTE; - case JCHAR_KIND: - return JCHAR; - case JSHORT_KIND: - return JSHORT; - case JINT_KIND: - return JINT; - case JLONG_KIND: - return JLONG; - case JFLOAT_KIND: - return JFLOAT; - case JDOUBLE_KIND: - return JDOUBLE; - case JBOOLEAN_KIND: - return JBOOLEAN; - default: - throw new IllegalArgumentException("The Java " + typeName + " type is not yet supported."); - } - } - - static JArrayType getJArrayTypeFromTypeName(String typeName, byte dimensions) { - - JArrayType arrayType = new JArrayType(getJTypeFromTypeName(typeName)); - int i = 1; - while (i < ((int) dimensions)) { - arrayType = new JArrayType(arrayType); - i += 1; - } - - return arrayType; - } - - static JType getJTypeForBType(BType type) { - switch (type.tag) { - case INT: - return jLong; - case BYTE: - return jInt; - case BOOLEAN: - return jBoolean; - case FLOAT: - return jFloat; - default: - return new JRefType(OBJECT); - } - } - - /** - * Java array type. - * - * @since 1.2.0 - */ - public static class JArrayType extends JType { - - JType elementType; - - JArrayType(JType elementType) { - - super(JARRAY); - this.elementType = elementType; - } - } - - /** - * Java referenced type. - * - * @since 1.2.0 - */ - public static class JRefType extends JType { - - public String typeValue; - boolean isInterface = false; - boolean isArray = false; - - public JRefType(String typeValue) { - - super(JREF); - this.typeValue = typeValue; - } - } -} diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/ParamTypeConstraint.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/ParamTypeConstraint.java index 4b14a728f9ce..60abfd4c2717 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/ParamTypeConstraint.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/ParamTypeConstraint.java @@ -27,7 +27,7 @@ class ParamTypeConstraint { static final ParamTypeConstraint NO_CONSTRAINT = new ParamTypeConstraint(null); - private Class constraint; + private final Class constraint; ParamTypeConstraint(Class constraint) { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/ConfigMethodGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/ConfigMethodGen.java index 7c377427e544..1618d381a41d 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/ConfigMethodGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/ConfigMethodGen.java @@ -23,9 +23,11 @@ import io.ballerina.tools.text.LineRange; import org.ballerinalang.model.elements.PackageID; import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.wso2.ballerinalang.compiler.bir.codegen.BallerinaClassWriter; +import org.wso2.ballerinalang.compiler.bir.codegen.JarEntries; import org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil; import org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants; import org.wso2.ballerinalang.compiler.bir.codegen.JvmTypeGen; @@ -37,7 +39,7 @@ import org.wso2.ballerinalang.util.Flags; import java.util.List; -import java.util.Map; +import java.util.Set; import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; import static org.objectweb.asm.Opcodes.AASTORE; @@ -58,15 +60,17 @@ import static org.objectweb.asm.Opcodes.INVOKESPECIAL; import static org.objectweb.asm.Opcodes.INVOKESTATIC; import static org.objectweb.asm.Opcodes.NEW; +import static org.objectweb.asm.Opcodes.PUTSTATIC; import static org.objectweb.asm.Opcodes.RETURN; import static org.objectweb.asm.Opcodes.V17; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CLASS_FILE_SUFFIX; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CONFIGURATION_CLASS_NAME; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CONFIGURE_INIT; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CONFIGURE_INIT_ATTEMPTED; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CURRENT_MODULE_INIT; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CURRENT_MODULE_VAR_NAME; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.HASH_MAP; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.JVM_INIT_METHOD; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.JVM_STATIC_INIT_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.LAUNCH_UTILS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_INIT_CLASS_NAME; @@ -74,9 +78,9 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.POPULATE_CONFIG_DATA_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.VARIABLE_KEY; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.ADD_MODULE_CONFIG_DATA; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_JBOOLEAN_TYPE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_MODULE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_CONFIG; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_CONFIGURABLES; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INTI_VARIABLE_KEY; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.POPULATE_CONFIG_DATA; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.RETURN_OBJECT; @@ -90,12 +94,13 @@ public class ConfigMethodGen { String innerClassName; - public void generateConfigMapper(List imprtMods, BIRNode.BIRPackage pkg, String moduleInitClass, + public void generateConfigMapper(Set imprtMods, BIRNode.BIRPackage pkg, String moduleInitClass, JvmConstantsGen jvmConstantsGen, TypeHashVisitor typeHashVisitor, - Map jarEntries, SymbolTable symbolTable) { + JarEntries jarEntries, SymbolTable symbolTable) { innerClassName = JvmCodeGenUtil.getModuleLevelClassName(pkg.packageID, CONFIGURATION_CLASS_NAME); ClassWriter cw = new BallerinaClassWriter(COMPUTE_FRAMES); cw.visit(V17, ACC_PUBLIC | ACC_SUPER, innerClassName, null, OBJECT, null); + generateStaticFields(cw, innerClassName); MethodVisitor mv = cw.visitMethod(ACC_PRIVATE, JVM_INIT_METHOD, VOID_METHOD_DESC, null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); @@ -104,7 +109,7 @@ public void generateConfigMapper(List imprtMods, BIRNode.BIRPackage p JvmCodeGenUtil.visitMaxStackForMethod(mv, JVM_INIT_METHOD, innerClassName); mv.visitEnd(); - generateConfigInit(cw, moduleInitClass, imprtMods, pkg.packageID); + generateConfigInit(cw, imprtMods, pkg.packageID, innerClassName); populateConfigDataMethod(cw, moduleInitClass, pkg, new JvmTypeGen(jvmConstantsGen, pkg.packageID, typeHashVisitor, symbolTable)); @@ -112,27 +117,33 @@ public void generateConfigMapper(List imprtMods, BIRNode.BIRPackage p jarEntries.put(innerClassName + CLASS_FILE_SUFFIX, cw.toByteArray()); } - private void generateConfigInit(ClassWriter cw, String moduleInitClass, List imprtMods, - PackageID packageID) { + private void generateStaticFields(ClassWriter cw, String innerClassName) { + MethodVisitor mv = cw.visitMethod(ACC_STATIC, JVM_STATIC_INIT_METHOD, VOID_METHOD_DESC, null, null); + FieldVisitor fv = cw.visitField(ACC_PUBLIC + ACC_STATIC, CONFIGURE_INIT_ATTEMPTED, GET_JBOOLEAN_TYPE, + null, null); + fv.visitEnd(); + mv.visitInsn(ICONST_0); + mv.visitFieldInsn(PUTSTATIC, innerClassName, CONFIGURE_INIT_ATTEMPTED, GET_JBOOLEAN_TYPE); + mv.visitInsn(RETURN); + JvmCodeGenUtil.visitMaxStackForMethod(mv, JVM_STATIC_INIT_METHOD, innerClassName); + mv.visitEnd(); + } + + private void generateConfigInit(ClassWriter cw, Set imprtMods, PackageID packageID, + String innerClassName) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, CONFIGURE_INIT, INIT_CONFIG, null, null); mv.visitCode(); - - mv.visitTypeInsn(NEW, HASH_MAP); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, HASH_MAP, JVM_INIT_METHOD, VOID_METHOD_DESC, false); - - mv.visitVarInsn(ASTORE, 3); - + mv.visitFieldInsn(GETSTATIC, innerClassName, CONFIGURE_INIT_ATTEMPTED, GET_JBOOLEAN_TYPE); + Label labelIf = new Label(); + mv.visitJumpInsn(IFEQ, labelIf); + mv.visitInsn(RETURN); + mv.visitLabel(labelIf); + mv.visitInsn(ICONST_1); + mv.visitFieldInsn(PUTSTATIC, innerClassName, CONFIGURE_INIT_ATTEMPTED, GET_JBOOLEAN_TYPE); for (PackageID id : imprtMods) { - generateInvokeConfiguration(mv, id); + generateInvokeConfigureInit(mv, id); } generateInvokeConfiguration(mv, packageID); - mv.visitFieldInsn(GETSTATIC, moduleInitClass, CURRENT_MODULE_VAR_NAME, GET_MODULE); - mv.visitVarInsn(ALOAD, 3); - mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); - mv.visitVarInsn(ALOAD, 2); - mv.visitMethodInsn(INVOKESTATIC, LAUNCH_UTILS, "initConfigurableVariables", INIT_CONFIGURABLES, false); mv.visitInsn(RETURN); JvmCodeGenUtil.visitMaxStackForMethod(mv, CONFIGURE_INIT, innerClassName); mv.visitEnd(); @@ -145,18 +156,26 @@ private void generateInvokeConfiguration(MethodVisitor mv, PackageID id) { mv.visitMethodInsn(INVOKESTATIC, moduleClass, POPULATE_CONFIG_DATA_METHOD, POPULATE_CONFIG_DATA, false); mv.visitVarInsn(ASTORE, 4); - mv.visitVarInsn(ALOAD, 4); mv.visitInsn(ARRAYLENGTH); Label elseLabel = new Label(); mv.visitJumpInsn(IFEQ, elseLabel); - mv.visitVarInsn(ALOAD, 3); + mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETSTATIC, initClass, CURRENT_MODULE_VAR_NAME, GET_MODULE); mv.visitVarInsn(ALOAD, 4); mv.visitMethodInsn(INVOKESTATIC, LAUNCH_UTILS, "addModuleConfigData", ADD_MODULE_CONFIG_DATA, false); mv.visitLabel(elseLabel); } + private void generateInvokeConfigureInit(MethodVisitor mv, PackageID id) { + String configClass = JvmCodeGenUtil.getModuleLevelClassName(id, CONFIGURATION_CLASS_NAME); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + mv.visitVarInsn(ALOAD, 3); + mv.visitMethodInsn(INVOKESTATIC, configClass, CONFIGURE_INIT, INIT_CONFIG, false); + } + private void populateConfigDataMethod(ClassWriter cw, String moduleClass, BIRNode.BIRPackage module, JvmTypeGen jvmTypeGen) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, POPULATE_CONFIG_DATA_METHOD, diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/FrameClassGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/FrameClassGen.java index ce9342a01919..3a116ac0efba 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/FrameClassGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/FrameClassGen.java @@ -23,13 +23,13 @@ import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Opcodes; import org.wso2.ballerinalang.compiler.bir.codegen.BallerinaClassWriter; +import org.wso2.ballerinalang.compiler.bir.codegen.JarEntries; import org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; import org.wso2.ballerinalang.compiler.semantics.model.types.BType; import org.wso2.ballerinalang.compiler.util.TypeTags; import java.util.List; -import java.util.Map; import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; import static org.objectweb.asm.Opcodes.ACC_SUPER; @@ -46,13 +46,13 @@ */ public class FrameClassGen { - public void generateFrameClasses(BIRNode.BIRPackage pkg, Map pkgEntries) { + public void generateFrameClasses(BIRNode.BIRPackage pkg, JarEntries pkgEntries) { pkg.functions.forEach( func -> generateFrameClassForFunction(pkg.packageID, func, pkgEntries, null)); for (BIRNode.BIRTypeDefinition typeDef : pkg.typeDefs) { List attachedFuncs = typeDef.attachedFuncs; - if (attachedFuncs == null || attachedFuncs.size() == 0) { + if (attachedFuncs == null || attachedFuncs.isEmpty()) { continue; } @@ -70,7 +70,7 @@ public void generateFrameClasses(BIRNode.BIRPackage pkg, Map pkg } private void generateFrameClassForFunction(PackageID packageID, BIRNode.BIRFunction func, - Map pkgEntries, + JarEntries pkgEntries, BType attachedType) { String frameClassName = MethodGenUtils.getFrameClassName(JvmCodeGenUtil.getPackageName(packageID), func.name.value, attachedType); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/InitMethodGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/InitMethodGen.java index 3a29c584877e..4393d2ae2c46 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/InitMethodGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/InitMethodGen.java @@ -21,15 +21,19 @@ import io.ballerina.identifier.Utils; import org.ballerinalang.model.elements.PackageID; import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; import org.wso2.ballerinalang.compiler.bir.codegen.JvmCastGen; import org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil; import org.wso2.ballerinalang.compiler.bir.codegen.JvmPackageGen; import org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures; +import org.wso2.ballerinalang.compiler.bir.codegen.internal.AsyncDataCollector; import org.wso2.ballerinalang.compiler.bir.codegen.internal.JavaClass; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.BIRFunctionWrapper; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JIMethodCLICall; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JIMethodCall; +import org.wso2.ballerinalang.compiler.bir.codegen.model.BIRFunctionWrapper; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JIMethodCLICall; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JIMethodCall; +import org.wso2.ballerinalang.compiler.bir.codegen.split.JvmConstantsGen; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; import org.wso2.ballerinalang.compiler.bir.model.BIRNonTerminator; import org.wso2.ballerinalang.compiler.bir.model.BIROperand; @@ -51,13 +55,16 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Set; import static org.ballerinalang.model.symbols.SymbolOrigin.VIRTUAL; import static org.objectweb.asm.Opcodes.AALOAD; +import static org.objectweb.asm.Opcodes.AASTORE; import static org.objectweb.asm.Opcodes.ACC_PUBLIC; import static org.objectweb.asm.Opcodes.ACC_STATIC; import static org.objectweb.asm.Opcodes.ACONST_NULL; import static org.objectweb.asm.Opcodes.ALOAD; +import static org.objectweb.asm.Opcodes.ANEWARRAY; import static org.objectweb.asm.Opcodes.ASTORE; import static org.objectweb.asm.Opcodes.BIPUSH; import static org.objectweb.asm.Opcodes.CHECKCAST; @@ -66,25 +73,38 @@ import static org.objectweb.asm.Opcodes.GETSTATIC; import static org.objectweb.asm.Opcodes.ICONST_0; import static org.objectweb.asm.Opcodes.ICONST_1; +import static org.objectweb.asm.Opcodes.IFNULL; import static org.objectweb.asm.Opcodes.INVOKESPECIAL; import static org.objectweb.asm.Opcodes.INVOKESTATIC; import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; import static org.objectweb.asm.Opcodes.LRETURN; import static org.objectweb.asm.Opcodes.NEW; +import static org.objectweb.asm.Opcodes.PUTFIELD; import static org.objectweb.asm.Opcodes.RETURN; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CLI_SPEC; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CREATE_TYPES_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CURRENT_MODULE_INIT; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CURRENT_MODULE_STOP; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.FUTURE_VALUE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.GET_TEST_EXECUTION_STATE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.GRACEFUL_EXIT_METHOD_NAME; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.HANDLE_STOP_PANIC_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.JVM_INIT_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.LAMBDA_PREFIX; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MAIN_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_EXECUTE_METHOD; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_INIT_CLASS_NAME; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_INIT_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_START_METHOD; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_STOP_METHOD; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.OBJECT; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.PANIC_FIELD; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.PREDEFINED_TYPES; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.RUNTIME_REGISTRY_CLASS; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.RUNTIME_UTILS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.SCHEDULER; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.SCHEDULER_START_METHOD; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.STACK; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.STRAND; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.STRAND_CLASS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.TEST_EXECUTE_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.TEST_EXECUTION_STATE; @@ -92,10 +112,16 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.ADD_VALUE_CREATOR; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_MAIN_ARGS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_SCHEDULER; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_STRAND; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_THROWABLE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GRACEFUL_EXIT_METHOD; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.HANDLE_STOP_PANIC; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.LAMBDA_STOP_DYNAMIC; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.LOAD_NULL_TYPE; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.MODULE_STOP; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.RETURN_OBJECT; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.SET_STRAND; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.STACK_FRAMES; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.VOID_METHOD_DESC; import static org.wso2.ballerinalang.compiler.util.CompilerUtils.getMajorVersion; @@ -122,22 +148,15 @@ public InitMethodGen(SymbolTable symbolTable) { * @param cw class visitor * @param pkg bir package * @param initClass module init class - * @param depMods dependent module list */ - public void generateLambdaForPackageInits(ClassWriter cw, BIRNode.BIRPackage pkg, String initClass, - List depMods) { + public void generateLambdaForPackageInit(ClassWriter cw, BIRNode.BIRPackage pkg, String initClass) { //need to generate lambda for package Init as well, if exist if (!MethodGenUtils.hasInitFunction(pkg)) { return; } - String funcName = MethodGenUtils.calculateLambdaStopFuncName(pkg.packageID); MethodVisitor mv = visitFunction(cw, funcName); invokeStopFunction(initClass, mv, funcName); - for (PackageID id : depMods) { - String jvmClass = JvmCodeGenUtil.getPackageName(id) + MODULE_INIT_CLASS_NAME; - generateLambdaForDepModStopFunc(cw, id, jvmClass); - } } public void generateLambdaForModuleExecuteFunction(ClassWriter cw, String initClass, JvmCastGen jvmCastGen, @@ -183,12 +202,6 @@ public void generateLambdaForModuleExecuteFunction(ClassWriter cw, String initCl MethodGenUtils.visitReturn(mv, lambdaFuncName, initClass); } - private void generateLambdaForDepModStopFunc(ClassWriter cw, PackageID pkgID, String initClass) { - String lambdaName = MethodGenUtils.calculateLambdaStopFuncName(pkgID); - MethodVisitor mv = visitFunction(cw, lambdaName); - invokeStopFunction(initClass, mv, lambdaName); - } - private MethodVisitor visitFunction(ClassWriter cw, String funcName) { MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, funcName, LAMBDA_STOP_DYNAMIC, null, null); mv.visitCode(); @@ -208,14 +221,13 @@ private void invokeStopFunction(String initClass, MethodVisitor mv, String metho } public void generateModuleInitializer(ClassWriter cw, BIRNode.BIRPackage module, String typeOwnerClass, - String moduleTypeClass) { + String moduleInitClass) { // Using object return type since this is similar to a ballerina function without a return. // A ballerina function with no returns is equivalent to a function with nil-return. MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, CURRENT_MODULE_INIT, RETURN_OBJECT, null, null); mv.visitCode(); - - mv.visitMethodInsn(INVOKESTATIC, moduleTypeClass, CREATE_TYPES_METHOD, VOID_METHOD_DESC, false); + mv.visitMethodInsn(INVOKESTATIC, moduleInitClass, CREATE_TYPES_METHOD, VOID_METHOD_DESC, false); mv.visitTypeInsn(NEW, typeOwnerClass); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, typeOwnerClass, JVM_INIT_METHOD, VOID_METHOD_DESC, false); @@ -236,9 +248,104 @@ public void generateModuleInitializer(ClassWriter cw, BIRNode.BIRPackage module, MethodGenUtils.visitReturn(mv, CURRENT_MODULE_INIT, typeOwnerClass); } + public void generateModuleStop(ClassWriter cw, String moduleInitClass, AsyncDataCollector asyncDataCollector, + JvmConstantsGen jvmConstantsGen) { + // Using object return type since this is similar to a ballerina function without a return. + // A ballerina function with no returns is equivalent to a function with nil-return. + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, CURRENT_MODULE_STOP, + JvmSignatures.CURRENT_MODULE_STOP, null, null); + mv.visitCode(); + + // Create a scheduler. A new scheduler is used here, to make the stop function to not + // depend/wait on whatever is being running on the background. eg: a busy loop in the main. + mv.visitTypeInsn(NEW, SCHEDULER); + mv.visitInsn(DUP); + mv.visitInsn(ICONST_1); + mv.visitInsn(ICONST_0); + mv.visitMethodInsn(INVOKESPECIAL, SCHEDULER, JVM_INIT_METHOD, "(IZ)V", false); + mv.visitVarInsn(ASTORE, 1); // Scheduler var1 + String lambdaName = generateStopDynamicLambdaBody(cw, moduleInitClass); + generateCallStopDynamicLambda(mv, lambdaName, moduleInitClass, asyncDataCollector, jvmConstantsGen); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 3); + mv.visitMethodInsn(INVOKESTATIC, moduleInitClass, MODULE_STOP_METHOD, MODULE_STOP, false); + mv.visitInsn(RETURN); + JvmCodeGenUtil.visitMaxStackForMethod(mv, CURRENT_MODULE_STOP, moduleInitClass); + mv.visitEnd(); + } + + private String generateStopDynamicLambdaBody(ClassWriter cw, String initClass) { + String lambdaName = LAMBDA_PREFIX + "stopdynamic"; + MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC + ACC_STATIC, lambdaName, LAMBDA_STOP_DYNAMIC, null, null); + mv.visitCode(); + MethodGenUtils.callSetDaemonStrand(mv); + generateCallSchedulerStopDynamicListeners(mv, lambdaName, initClass); + return lambdaName; + } + + private void generateCallSchedulerStopDynamicListeners(MethodVisitor mv, String lambdaName, String initClass) { + mv.visitVarInsn(ALOAD, 0); + mv.visitInsn(ICONST_1); + mv.visitInsn(AALOAD); + mv.visitTypeInsn(CHECKCAST, RUNTIME_REGISTRY_CLASS); + mv.visitVarInsn(ALOAD, 0); + mv.visitInsn(ICONST_0); + mv.visitInsn(AALOAD); + mv.visitTypeInsn(CHECKCAST, STRAND_CLASS); + mv.visitMethodInsn(INVOKEVIRTUAL, RUNTIME_REGISTRY_CLASS, "gracefulStop", SET_STRAND, false); + mv.visitInsn(ACONST_NULL); + MethodGenUtils.visitReturn(mv, lambdaName, initClass); + } + + private void generateCallStopDynamicLambda(MethodVisitor mv, String lambdaName, String moduleInitClass, + AsyncDataCollector asyncDataCollector, JvmConstantsGen jvmConstantsGen) { + addRuntimeRegistryAsParameter(mv); + generateMethodBody(mv, moduleInitClass, lambdaName, asyncDataCollector, jvmConstantsGen); + // handle any runtime errors + Label labelIf = new Label(); + mv.visitVarInsn(ALOAD, 3); + mv.visitFieldInsn(GETFIELD, FUTURE_VALUE, PANIC_FIELD, GET_THROWABLE); + mv.visitJumpInsn(IFNULL, labelIf); + mv.visitVarInsn(ALOAD, 3); + mv.visitFieldInsn(GETFIELD, FUTURE_VALUE, PANIC_FIELD, GET_THROWABLE); + mv.visitMethodInsn(INVOKESTATIC, RUNTIME_UTILS, HANDLE_STOP_PANIC_METHOD, HANDLE_STOP_PANIC, false); + mv.visitLabel(labelIf); + } + + private void addRuntimeRegistryAsParameter(MethodVisitor mv) { + mv.visitIntInsn(BIPUSH, 2); + mv.visitTypeInsn(ANEWARRAY, OBJECT); + mv.visitVarInsn(ASTORE, 2); + mv.visitVarInsn(ALOAD, 2); + mv.visitInsn(ICONST_1); + mv.visitVarInsn(ALOAD, 0); + mv.visitInsn(AASTORE); + mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 2); + } + + private void generateMethodBody(MethodVisitor mv, String initClass, String stopFuncName, + AsyncDataCollector asyncDataCollector, JvmConstantsGen jvmConstantsGen) { + JvmCodeGenUtil.createFunctionPointer(mv, initClass, stopFuncName); + mv.visitInsn(ACONST_NULL); + mv.visitFieldInsn(GETSTATIC, PREDEFINED_TYPES, "TYPE_NULL", LOAD_NULL_TYPE); + MethodGenUtils.submitToScheduler(mv, jvmConstantsGen.getStrandMetadataConstantsClass(), "stop", + asyncDataCollector); + mv.visitVarInsn(ASTORE, 3); + mv.visitVarInsn(ALOAD, 3); + mv.visitFieldInsn(GETFIELD, FUTURE_VALUE, STRAND, GET_STRAND); + mv.visitTypeInsn(NEW, STACK); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, STACK, JVM_INIT_METHOD, VOID_METHOD_DESC, false); + mv.visitFieldInsn(PUTFIELD, STRAND_CLASS, MethodGenUtils.FRAMES, STACK_FRAMES); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKEVIRTUAL, SCHEDULER, SCHEDULER_START_METHOD, VOID_METHOD_DESC, false); + } + public void enrichPkgWithInitializers(Map birFunctionMap, Map jvmClassMap, String typeOwnerClass, - BIRNode.BIRPackage pkg, List moduleImports, + BIRNode.BIRPackage pkg, Set moduleImports, boolean serviceEPAvailable, BIRNode.BIRFunction mainFunc, BIRNode.BIRFunction testExecuteFunc) { JavaClass javaClass = jvmClassMap.get(typeOwnerClass); @@ -352,7 +459,7 @@ private BIRNode.BIRFunction generateExecuteFunction(BIRNode.BIRPackage pkg, bool lastBB = addTestExecuteInvocationWithGracefulExitCall(modExecFunc, pkg.packageID, retVarRef, functionArgs, Collections.emptyList(), typeOwnerClass); } else if (!serviceEPAvailable && !JvmPackageGen.isLangModule(pkg.packageID)) { - lastBB = addInvocationForGracefulExitCall(modExecFunc, retVarRef, boolRef, typeOwnerClass); + lastBB = addInvocationForGracefulExitCall(modExecFunc, typeOwnerClass); } lastBB.terminator = new BIRTerminator.Return(null); return modExecFunc; @@ -421,7 +528,7 @@ private BIRNode.BIRGlobalVariableDcl getDefaultFuncFPGlobalVar(Name name, return null; } - private BIRNode.BIRFunction generateDefaultFunction(List imprtMods, BIRNode.BIRPackage pkg, + private BIRNode.BIRFunction generateDefaultFunction(Set imprtMods, BIRNode.BIRPackage pkg, String funcName, String initName) { nextId = 0; nextVarId = 0; @@ -431,16 +538,15 @@ private BIRNode.BIRFunction generateDefaultFunction(List imprtMods, B BIROperand retVarRef = new BIROperand(retVar); BInvokableType funcType = new BInvokableType(Collections.emptyList(), null, errorOrNilType, null); - BIRNode.BIRFunction modInitFunc = new BIRNode.BIRFunction(null, new Name(funcName), 0, funcType, null, 0, - VIRTUAL); + BIRNode.BIRFunction modInitFunc = new BIRNode.BIRFunction(symbolTable.builtinPos, new Name(funcName), 0, + funcType, null, 0, VIRTUAL); modInitFunc.localVars.add(retVar); addAndGetNextBasicBlock(modInitFunc); BIRNode.BIRVariableDcl boolVal = addAndGetNextVar(modInitFunc, symbolTable.booleanType); BIROperand boolRef = new BIROperand(boolVal); - + String initFuncName = MethodGenUtils.encodeModuleSpecialFuncName(funcName); for (PackageID id : imprtMods) { - String initFuncName = MethodGenUtils.encodeModuleSpecialFuncName(initName); addCheckedInvocation(modInitFunc, id, initFuncName, retVarRef, boolRef); } @@ -466,8 +572,8 @@ private Name getNextVarId() { return new Name(varIdPrefix + nextVarId); } - private BIRNode.BIRBasicBlock addInvocationForGracefulExitCall(BIRNode.BIRFunction func, BIROperand retVar, - BIROperand boolRef, String typeOwnerClass) { + private BIRNode.BIRBasicBlock addInvocationForGracefulExitCall(BIRNode.BIRFunction func, + String typeOwnerClass) { BIRNode.BIRBasicBlock lastBB = func.basicBlocks.get(func.basicBlocks.size() - 1); BIRNode.BIRBasicBlock nextBB = addAndGetNextBasicBlock(func); lastBB.terminator = getExitMethodCall(nextBB, typeOwnerClass); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/LambdaGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/LambdaGen.java index e8cf50bfb1e3..db6a0d634707 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/LambdaGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/LambdaGen.java @@ -25,11 +25,16 @@ import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; +import org.wso2.ballerinalang.compiler.bir.codegen.BallerinaClassWriter; +import org.wso2.ballerinalang.compiler.bir.codegen.JarEntries; import org.wso2.ballerinalang.compiler.bir.codegen.JvmCastGen; import org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil; import org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants; import org.wso2.ballerinalang.compiler.bir.codegen.JvmPackageGen; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.BIRFunctionWrapper; +import org.wso2.ballerinalang.compiler.bir.codegen.internal.AsyncDataCollector; +import org.wso2.ballerinalang.compiler.bir.codegen.internal.LambdaClass; +import org.wso2.ballerinalang.compiler.bir.codegen.internal.LambdaFunction; +import org.wso2.ballerinalang.compiler.bir.codegen.model.BIRFunctionWrapper; import org.wso2.ballerinalang.compiler.bir.model.BIRAbstractInstruction; import org.wso2.ballerinalang.compiler.bir.model.BIRInstruction; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; @@ -37,7 +42,6 @@ import org.wso2.ballerinalang.compiler.bir.model.BIROperand; import org.wso2.ballerinalang.compiler.bir.model.BIRTerminator; import org.wso2.ballerinalang.compiler.bir.model.InstructionKind; -import org.wso2.ballerinalang.compiler.semantics.model.SymbolTable; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BInvokableSymbol; import org.wso2.ballerinalang.compiler.semantics.model.symbols.BPackageSymbol; import org.wso2.ballerinalang.compiler.semantics.model.types.BFutureType; @@ -48,10 +52,15 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; +import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; import static org.objectweb.asm.Opcodes.AALOAD; import static org.objectweb.asm.Opcodes.AASTORE; +import static org.objectweb.asm.Opcodes.ACC_PRIVATE; +import static org.objectweb.asm.Opcodes.ACC_PUBLIC; import static org.objectweb.asm.Opcodes.ACC_STATIC; +import static org.objectweb.asm.Opcodes.ACC_SUPER; import static org.objectweb.asm.Opcodes.ACONST_NULL; import static org.objectweb.asm.Opcodes.ALOAD; import static org.objectweb.asm.Opcodes.ANEWARRAY; @@ -67,20 +76,31 @@ import static org.objectweb.asm.Opcodes.IFEQ; import static org.objectweb.asm.Opcodes.IFNULL; import static org.objectweb.asm.Opcodes.INVOKEINTERFACE; +import static org.objectweb.asm.Opcodes.INVOKESPECIAL; import static org.objectweb.asm.Opcodes.INVOKESTATIC; import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; import static org.objectweb.asm.Opcodes.POP; import static org.objectweb.asm.Opcodes.PUTFIELD; +import static org.objectweb.asm.Opcodes.V17; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.BLOCKED_ON_EXTERN_FIELD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.B_OBJECT; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CALL_FUNCTION; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CLASS_FILE_SUFFIX; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.INT_VALUE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.IS_BLOCKED_ON_EXTERN_FIELD; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_FUNCTION_CALLS_CLASS_NAME; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.OBJECT; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.OBJECT_SELF_INSTANCE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.PANIC_FIELD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.STRAND_CLASS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.BOBJECT_CALL; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.FUNCTION_CALL; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_BERROR; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_OBJECT; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INITIAL_METHOD_DESC; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.VOID_METHOD_DESC; +import static org.wso2.ballerinalang.compiler.bir.codegen.split.constants.JvmConstantGenCommons.genMethodReturn; + /** * Generates Jvm byte code for the lambda method. * @@ -88,76 +108,114 @@ */ public class LambdaGen { - private final SymbolTable symbolTable; private final JvmPackageGen jvmPackageGen; private final JvmCastGen jvmCastGen; + private final BIRNode.BIRPackage module; - public LambdaGen(JvmPackageGen jvmPackageGen, JvmCastGen jvmCastGen) { + public LambdaGen(JvmPackageGen jvmPackageGen, JvmCastGen jvmCastGen, BIRNode.BIRPackage module) { this.jvmPackageGen = jvmPackageGen; - this.symbolTable = jvmPackageGen.symbolTable; this.jvmCastGen = jvmCastGen; + this.module = module; + } + + public void generateLambdaClasses(AsyncDataCollector asyncDataCollector, + JarEntries jarEntries) { + Map lambdaClasses = asyncDataCollector.getLambdaClasses(); + if (lambdaClasses.isEmpty()) { + return; + } + for (Map.Entry entry : lambdaClasses.entrySet()) { + String lambdaClassName = entry.getKey(); + LambdaClass lambdaClass = entry.getValue(); + ClassWriter cw = new BallerinaClassWriter(COMPUTE_FRAMES); + cw.visitSource(lambdaClass.sourceFileName, null); + generateConstantsClassInit(cw, lambdaClassName); + List lambdaList = lambdaClass.lambdaFunctionList; + for (LambdaFunction recordDefaultValueLambda : lambdaList) { + generateLambdaMethod(recordDefaultValueLambda.callInstruction, cw, + recordDefaultValueLambda.lambdaName, lambdaClassName); + } + cw.visitEnd(); + jarEntries.put(lambdaClassName + CLASS_FILE_SUFFIX, cw.toByteArray()); + } } - public void generateLambdaMethod(BIRInstruction ins, ClassWriter cw, String lambdaName, String className) { + private void generateConstantsClassInit(ClassWriter cw, String lambdaClassName) { + cw.visit(V17, ACC_PUBLIC | ACC_SUPER, lambdaClassName, null, JvmConstants.OBJECT, null); + MethodVisitor methodVisitor = + cw.visitMethod(ACC_PRIVATE, JvmConstants.JVM_INIT_METHOD, VOID_METHOD_DESC, null, null); + methodVisitor.visitCode(); + Label methodStartLabel = new Label(); + methodVisitor.visitLabel(methodStartLabel); + methodVisitor.visitVarInsn(ALOAD, 0); + methodVisitor.visitMethodInsn(INVOKESPECIAL, JvmConstants.OBJECT, JvmConstants.JVM_INIT_METHOD, + VOID_METHOD_DESC, false); + Label methodEndLabel = new Label(); + methodVisitor.visitLabel(methodEndLabel); + methodVisitor.visitLocalVariable(OBJECT_SELF_INSTANCE, GET_OBJECT, null, methodStartLabel, methodEndLabel, 0); + genMethodReturn(methodVisitor); + } + + private void generateLambdaMethod(BIRInstruction ins, ClassWriter cw, String lambdaName, String className) { LambdaDetails lambdaDetails = getLambdaDetails(ins); - MethodVisitor mv = getMethodVisitorAndLoadFirst(cw, lambdaName, lambdaDetails, ins); + boolean isSamePkg = JvmCodeGenUtil.isSameModule(module.packageID, lambdaDetails.packageID); + MethodVisitor mv = getMethodVisitorAndLoadFirst(cw, lambdaName, lambdaDetails, ins, isSamePkg); List paramBTypes = new ArrayList<>(); if (ins.getKind() == InstructionKind.ASYNC_CALL) { - handleAsyncCallLambda((BIRTerminator.AsyncCall) ins, lambdaDetails, mv, paramBTypes); + handleAsyncCallLambda((BIRTerminator.AsyncCall) ins, lambdaDetails, mv, paramBTypes, isSamePkg); } else { - handleFpLambda((BIRNonTerminator.FPLoad) ins, lambdaDetails, mv, paramBTypes); + handleFpLambda((BIRNonTerminator.FPLoad) ins, lambdaDetails, mv, paramBTypes, isSamePkg); } MethodGenUtils.visitReturn(mv, lambdaName, className); } private void genNonVirtual(LambdaDetails lambdaDetails, MethodVisitor mv, List paramBTypes, - boolean isWorker) { - String jvmClass; - String methodDesc = getLambdaMethodDesc(paramBTypes, lambdaDetails.returnType, lambdaDetails.closureMapsCount, - isWorker); + boolean isWorker, boolean isSamePkg) { + String jvmClass, funcName, methodDesc; + if (!isSamePkg) { + // Use call method of function calls class to execute functions from imported modules + jvmClass = JvmCodeGenUtil.getModuleLevelClassName(lambdaDetails.packageID, + MODULE_FUNCTION_CALLS_CLASS_NAME); + funcName = CALL_FUNCTION; + methodDesc = FUNCTION_CALL; + mv.visitMethodInsn(INVOKESTATIC, jvmClass, funcName, methodDesc, false); + return; + } if (lambdaDetails.functionWrapper != null) { - jvmClass = lambdaDetails.functionWrapper.fullQualifiedClassName; + jvmClass = lambdaDetails.functionWrapper.fullQualifiedClassName(); } else { - String balFileName = lambdaDetails.funcSymbol.source; - - if (balFileName == null || !balFileName.endsWith(JvmConstants.BAL_EXTENSION)) { - balFileName = JvmConstants.MODULE_INIT_CLASS_NAME; - } - jvmClass = JvmCodeGenUtil.getModuleLevelClassName(lambdaDetails.packageID, JvmCodeGenUtil - .cleanupPathSeparators(balFileName)); + jvmClass = JvmCodeGenUtil.getModuleLevelClassName(lambdaDetails.packageID, + MODULE_FUNCTION_CALLS_CLASS_NAME); } + methodDesc = getLambdaMethodDesc(paramBTypes, lambdaDetails.returnType, lambdaDetails.closureMapsCount, + isWorker); mv.visitMethodInsn(INVOKESTATIC, jvmClass, lambdaDetails.encodedFuncName, methodDesc, false); jvmCastGen.addBoxInsn(mv, lambdaDetails.returnType); } private void handleAsyncCallLambda(BIRTerminator.AsyncCall ins, LambdaDetails lambdaDetails, MethodVisitor mv, - List paramBTypes) { + List paramBTypes, boolean isSamePkg) { if (ins.isVirtual) { handleLambdaVirtual(ins, lambdaDetails, mv); } else { - handleAsyncNonVirtual(lambdaDetails, mv, paramBTypes); + handleAsyncNonVirtual(lambdaDetails, mv, paramBTypes, isSamePkg); } } private void handleLambdaVirtual(BIRTerminator.AsyncCall ins, LambdaDetails lambdaDetails, MethodVisitor mv) { - boolean isBuiltinModule = JvmCodeGenUtil.isBallerinaBuiltinModule(lambdaDetails.packageID.orgName.getValue(), - lambdaDetails.packageID.name.getValue()); List paramTypes = ins.args; - genLoadDataForObjectAttachedLambdas(ins, mv, lambdaDetails.closureMapsCount, paramTypes, - isBuiltinModule); + genLoadDataForObjectAttachedLambdas(ins, mv, lambdaDetails.closureMapsCount, paramTypes); int paramIndex = 1; for (int paramTypeIndex = 1; paramTypeIndex < paramTypes.size(); paramTypeIndex++) { generateObjectArgs(mv, paramIndex); - paramIndex += 1; + paramIndex++; } - String methodDesc = BOBJECT_CALL; - mv.visitMethodInsn(INVOKEINTERFACE , B_OBJECT, "call", methodDesc, true); + mv.visitMethodInsn(INVOKEINTERFACE, B_OBJECT, CALL_FUNCTION, BOBJECT_CALL, true); } private void genLoadDataForObjectAttachedLambdas(BIRTerminator.AsyncCall ins, MethodVisitor mv, - int closureMapsCount, List paramTypes, - boolean isBuiltinModule) { + int closureMapsCount, List paramTypes) { mv.visitInsn(POP); mv.visitVarInsn(ALOAD, closureMapsCount); @@ -170,7 +228,7 @@ private void genLoadDataForObjectAttachedLambdas(BIRTerminator.AsyncCall ins, Me mv.visitInsn(AALOAD); mv.visitTypeInsn(CHECKCAST, STRAND_CLASS); - mv.visitLdcInsn(JvmCodeGenUtil.rewriteVirtualCallTypeName(ins.name.value)); + mv.visitLdcInsn(JvmCodeGenUtil.rewriteVirtualCallTypeName(ins.name.value, ref.variableDcl.type)); int objectArrayLength = paramTypes.size() - 1; mv.visitIntInsn(BIPUSH, objectArrayLength); mv.visitTypeInsn(ANEWARRAY, OBJECT); @@ -185,35 +243,44 @@ private void generateObjectArgs(MethodVisitor mv, int paramIndex) { mv.visitInsn(AASTORE); } - private void handleAsyncNonVirtual(LambdaDetails lambdaDetails, MethodVisitor mv, List paramBTypes) { - boolean isBuiltinModule = JvmCodeGenUtil.isBallerinaBuiltinModule(lambdaDetails.packageID.orgName.getValue(), - lambdaDetails.packageID.name.getValue()); + private void generateFpCallArgs(MethodVisitor mv, int paramIndex) { + mv.visitInsn(DUP); + mv.visitIntInsn(BIPUSH, paramIndex); + mv.visitVarInsn(ALOAD, 0); + mv.visitIntInsn(BIPUSH, paramIndex + 1); + mv.visitInsn(AALOAD); + mv.visitInsn(AASTORE); + } + + private void handleAsyncNonVirtual(LambdaDetails lambdaDetails, MethodVisitor mv, List paramBTypes, + boolean isSamePkg) { List paramTypes = getFpParamTypes(lambdaDetails); // load and cast param values= asyncIns.args; - int argIndex = 1; - for (BType paramType : paramTypes) { - mv.visitVarInsn(ALOAD, 0); - mv.visitIntInsn(BIPUSH, argIndex); - mv.visitInsn(AALOAD); - jvmCastGen.addUnboxInsn(mv, paramType); - paramBTypes.add(argIndex - 1, paramType); - argIndex += 1; + if (isSamePkg) { + int argIndex = 1; + for (BType paramType : paramTypes) { + mv.visitVarInsn(ALOAD, 0); + mv.visitIntInsn(BIPUSH, argIndex); + mv.visitInsn(AALOAD); + jvmCastGen.addUnboxInsn(mv, paramType); + paramBTypes.add(argIndex - 1, paramType); + argIndex++; + } + } else { + mv.visitIntInsn(BIPUSH, paramTypes.size()); + mv.visitTypeInsn(ANEWARRAY, OBJECT); + for (int paramIndex = 0; paramIndex < paramTypes.size(); paramIndex++) { + generateFpCallArgs(mv, paramIndex); + } } - genNonVirtual(lambdaDetails, mv, paramBTypes, false); - } - - private void addBooleanTypeToLambdaParamTypes(MethodVisitor mv, int arrayIndex, int paramIndex) { - mv.visitVarInsn(ALOAD, arrayIndex); - mv.visitIntInsn(BIPUSH, paramIndex); - mv.visitInsn(AALOAD); - jvmCastGen.addUnboxInsn(mv, symbolTable.booleanType); + genNonVirtual(lambdaDetails, mv, paramBTypes, false, isSamePkg); } private List getFpParamTypes(LambdaDetails lambdaDetails) { List paramTypes; if (lambdaDetails.functionWrapper != null) { - paramTypes = getInitialParamTypes(lambdaDetails.functionWrapper.func.type.paramTypes, - lambdaDetails.functionWrapper.func.argsCount); + paramTypes = getInitialParamTypes(lambdaDetails.functionWrapper.func().type.paramTypes, + lambdaDetails.functionWrapper.func().argsCount); } else { BInvokableType type = (BInvokableType) lambdaDetails.funcSymbol.type; if (type.restType == null) { @@ -226,23 +293,31 @@ private List getFpParamTypes(LambdaDetails lambdaDetails) { } private void handleFpLambda(BIRNonTerminator.FPLoad ins, LambdaDetails lambdaDetails, MethodVisitor mv, - List paramBTypes) { + List paramBTypes, boolean isSamePkg) { loadClosureMaps(lambdaDetails, mv); // load and cast param values - loadAndCastParamValues(ins, lambdaDetails, mv, paramBTypes); - genNonVirtual(lambdaDetails, mv, paramBTypes, ins.isWorker); + loadAndCastParamValues(ins, lambdaDetails, mv, paramBTypes, isSamePkg); + genNonVirtual(lambdaDetails, mv, paramBTypes, ins.isWorker, isSamePkg); } private void loadAndCastParamValues(BIRNonTerminator.FPLoad ins, LambdaDetails lambdaDetails, MethodVisitor mv, - List paramBTypes) { - int argIndex = 1; - for (BIRNode.BIRVariableDcl dcl : ins.params) { - mv.visitVarInsn(ALOAD, lambdaDetails.closureMapsCount); - mv.visitIntInsn(BIPUSH, argIndex); - mv.visitInsn(AALOAD); - jvmCastGen.addUnboxInsn(mv, dcl.type); - paramBTypes.add(argIndex - 1, dcl.type); - argIndex += 1; + List paramBTypes, boolean isSamePkg) { + if (isSamePkg) { + int argIndex = 1; + for (BIRNode.BIRVariableDcl dcl : ins.params) { + mv.visitVarInsn(ALOAD, lambdaDetails.closureMapsCount); + mv.visitIntInsn(BIPUSH, argIndex); + mv.visitInsn(AALOAD); + jvmCastGen.addUnboxInsn(mv, dcl.type); + paramBTypes.add(argIndex - 1, dcl.type); + argIndex++; + } + } else { + mv.visitIntInsn(BIPUSH, ins.params.size()); + mv.visitTypeInsn(ANEWARRAY, OBJECT); + for (int paramIndex = 0; paramIndex < ins.params.size(); paramIndex++) { + generateFpCallArgs(mv, paramIndex); + } } } @@ -252,23 +327,25 @@ private void loadClosureMaps(LambdaDetails lambdaDetails, MethodVisitor mv) { } } - private MethodVisitor getMethodVisitorAndLoadFirst(ClassWriter cw, String lambdaName, - LambdaDetails lambdaDetails, BIRInstruction ins) { + private MethodVisitor getMethodVisitorAndLoadFirst(ClassWriter cw, String lambdaName, LambdaDetails lambdaDetails, + BIRInstruction ins, boolean isSamePkg) { String closureMapsDesc = getMapValueDesc(lambdaDetails.closureMapsCount); MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC + ACC_STATIC, lambdaName, "(" + closureMapsDesc + "[L" + OBJECT + ";)L" + OBJECT + ";", null, null); mv.visitCode(); - // generate diagnostic position when generating lambda method + // generate diagnostic position when generating lambda method JvmCodeGenUtil.generateDiagnosticPos(((BIRAbstractInstruction) ins).pos, mv); // load strand as first arg - // strand and other args are in a object[] param. This param comes after closure maps. + // strand and other args are in an object[] param. This param comes after closure maps. // hence the closureMapsCount is equal to the array's param index. mv.visitVarInsn(ALOAD, lambdaDetails.closureMapsCount); mv.visitInsn(ICONST_0); mv.visitInsn(AALOAD); mv.visitTypeInsn(CHECKCAST, STRAND_CLASS); - + if (!isSamePkg) { + mv.visitLdcInsn(lambdaDetails.encodedFuncName); + } if ((ins.getKind() == InstructionKind.FP_LOAD) && ((BIRNonTerminator.FPLoad) ins).isWorker) { mv.visitVarInsn(ALOAD, lambdaDetails.closureMapsCount); mv.visitInsn(ICONST_1); @@ -276,7 +353,6 @@ private MethodVisitor getMethodVisitorAndLoadFirst(ClassWriter cw, String lambda mv.visitTypeInsn(CHECKCAST, INT_VALUE); mv.visitMethodInsn(INVOKEVIRTUAL, INT_VALUE, "intValue", "()I", false); } - if (lambdaDetails.isExternFunction) { generateBlockedOnExtern(lambdaDetails.closureMapsCount, mv); } @@ -296,8 +372,7 @@ private void generateBlockedOnExtern(int closureMapsCount, MethodVisitor mv) { mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKEVIRTUAL, STRAND_CLASS , IS_BLOCKED_ON_EXTERN_FIELD, "()Z", - false); + mv.visitMethodInsn(INVOKEVIRTUAL, STRAND_CLASS , IS_BLOCKED_ON_EXTERN_FIELD, "()Z", false); mv.visitJumpInsn(IFEQ, blockedOnExternLabel); mv.visitInsn(DUP); @@ -305,17 +380,14 @@ private void generateBlockedOnExtern(int closureMapsCount, MethodVisitor mv) { mv.visitFieldInsn(PUTFIELD, STRAND_CLASS , BLOCKED_ON_EXTERN_FIELD, "Z"); mv.visitInsn(DUP); - mv.visitFieldInsn(GETFIELD, STRAND_CLASS , PANIC_FIELD, - GET_BERROR); + mv.visitFieldInsn(GETFIELD, STRAND_CLASS , PANIC_FIELD, GET_BERROR); Label panicLabel = new Label(); mv.visitJumpInsn(IFNULL, panicLabel); mv.visitInsn(DUP); - mv.visitFieldInsn(GETFIELD, STRAND_CLASS , PANIC_FIELD, - GET_BERROR); + mv.visitFieldInsn(GETFIELD, STRAND_CLASS , PANIC_FIELD, GET_BERROR); mv.visitVarInsn(ASTORE, closureMapsCount + 1); mv.visitInsn(ACONST_NULL); - mv.visitFieldInsn(PUTFIELD, STRAND_CLASS , PANIC_FIELD, - GET_BERROR); + mv.visitFieldInsn(PUTFIELD, STRAND_CLASS , PANIC_FIELD, GET_BERROR); mv.visitVarInsn(ALOAD, closureMapsCount + 1); mv.visitInsn(ATHROW); mv.visitLabel(panicLabel); @@ -336,7 +408,7 @@ private LambdaDetails getLambdaDetails(BIRInstruction ins) { lambdaDetails = populateFpLambdaDetails((BIRNonTerminator.FPLoad) ins); } else { throw new BLangCompilerException("JVM lambda method generation is not supported for instruction " + - ins); + ins); } lambdaDetails.isExternFunction = isExternStaticFunctionCall(ins); populateLambdaReturnType(ins, lambdaDetails); @@ -384,33 +456,32 @@ private boolean isExternStaticFunctionCall(BIRInstruction callIns) { PackageID packageID; switch (kind) { - case CALL: + case CALL -> { BIRTerminator.Call call = (BIRTerminator.Call) callIns; if (call.isVirtual) { return false; } methodName = call.name.value; packageID = call.calleePkg; - break; - case ASYNC_CALL: + } + case ASYNC_CALL -> { BIRTerminator.AsyncCall asyncCall = (BIRTerminator.AsyncCall) callIns; methodName = asyncCall.name.value; packageID = asyncCall.calleePkg; - break; - case FP_LOAD: + } + case FP_LOAD -> { BIRNonTerminator.FPLoad fpLoad = (BIRNonTerminator.FPLoad) callIns; methodName = fpLoad.funcName.value; packageID = fpLoad.pkgId; - break; - default: - throw new BLangCompilerException("JVM static function call generation is not supported for " + - "instruction " + callIns); + } + default -> throw new BLangCompilerException("JVM static function call generation is not supported for " + + "instruction " + callIns); } String key = JvmCodeGenUtil.getPackageName(packageID) + methodName; BIRFunctionWrapper functionWrapper = jvmPackageGen.lookupBIRFunctionWrapper(key); - return functionWrapper != null && JvmCodeGenUtil.isExternFunc(functionWrapper.func); + return functionWrapper != null && JvmCodeGenUtil.isExternFunc(functionWrapper.func()); } private void populateLambdaReturnType(BIRInstruction ins, LambdaDetails lambdaDetails) { @@ -421,7 +492,7 @@ private void populateLambdaReturnType(BIRInstruction ins, LambdaDetails lambdaDe lambdaDetails.returnType = ((BInvokableType) ((BIRNonTerminator.FPLoad) ins).type).retType; } else { throw new BLangCompilerException("JVM generation is not supported for async return type " + - lambdaDetails.lhsType); + lambdaDetails.lhsType); } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/MainMethodGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/MainMethodGen.java index 2ede946b3a1c..e4bd8a182f6c 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/MainMethodGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/MainMethodGen.java @@ -26,9 +26,11 @@ import org.objectweb.asm.Opcodes; import org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil; import org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants; +import org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures; import org.wso2.ballerinalang.compiler.bir.codegen.JvmTypeGen; import org.wso2.ballerinalang.compiler.bir.codegen.internal.AsyncDataCollector; import org.wso2.ballerinalang.compiler.bir.codegen.internal.BIRVarToJVMIndexMap; +import org.wso2.ballerinalang.compiler.bir.codegen.split.JvmConstantsGen; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; import org.wso2.ballerinalang.compiler.semantics.model.SymbolTable; import org.wso2.ballerinalang.compiler.semantics.model.types.BType; @@ -67,12 +69,14 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CONFIGURATION_CLASS_NAME; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CONFIGURE_INIT; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CONFIG_DETAILS; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CURRENT_MODULE_STOP; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.CURRENT_MODULE_VAR_NAME; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.FUTURE_VALUE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.HANDLE_ALL_THROWABLE_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.HANDLE_RETURNED_ERROR_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.HANDLE_STOP_PANIC_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.HANDLE_THROWABLE_METHOD; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.HASH_MAP; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.JAVA_RUNTIME; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.JVM_INIT_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.LAMBDA_PREFIX; @@ -80,12 +84,10 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MAIN_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_EXECUTE_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_INIT_CLASS_NAME; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_STOP_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.OBJECT; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.OPERAND; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.OPTION; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.PANIC_FIELD; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.PATH; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.REPOSITORY_IMPL; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.RUNTIME_UTILS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.SCHEDULER; @@ -94,7 +96,6 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.STACK; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.STRAND; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.STRAND_CLASS; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.STRING_VALUE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.TEST_ARGUMENTS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.TEST_CONFIG_ARGS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.TEST_EXECUTION_STATE; @@ -105,9 +106,11 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_MAIN_ARGS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_MODULE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_OBJECT; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_PATH; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_RUNTIME; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_RUNTIME_REGISTRY_CLASS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_STRAND; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_STRING; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_STRING_ARRAY; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_TEST_CONFIG_PATH; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_THROWABLE; @@ -115,6 +118,7 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.HANDLE_THROWABLE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_CLI_SPEC; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_CONFIG; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_CONFIGURABLES; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_OPERAND; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_OPTION; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_RUNTIME_REGISTRY; @@ -138,15 +142,17 @@ public class MainMethodGen { private final BIRVarToJVMIndexMap indexMap; private final JvmTypeGen jvmTypeGen; private final AsyncDataCollector asyncDataCollector; + private final String strandMetadataClass; private final boolean isRemoteMgtEnabled; - public MainMethodGen(SymbolTable symbolTable, JvmTypeGen jvmTypeGen, AsyncDataCollector asyncDataCollector, - boolean isRemoteMgtEnabled) { + public MainMethodGen(SymbolTable symbolTable, JvmTypeGen jvmTypeGen, JvmConstantsGen jvmConstantsGen, + AsyncDataCollector asyncDataCollector, boolean isRemoteMgtEnabled) { this.symbolTable = symbolTable; // add main string[] args param first indexMap = new BIRVarToJVMIndexMap(1); this.jvmTypeGen = jvmTypeGen; this.asyncDataCollector = asyncDataCollector; + this.strandMetadataClass = jvmConstantsGen.getStrandMetadataConstantsClass(); this.isRemoteMgtEnabled = isRemoteMgtEnabled; } @@ -231,7 +237,7 @@ private void generateExecuteFunctionCall(String initClass, MethodVisitor mv, BIR private void generateModuleStopCall(String initClass, MethodVisitor mv) { mv.visitVarInsn(ALOAD, indexMap.get(SCHEDULER_VAR)); mv.visitMethodInsn(INVOKEVIRTUAL, SCHEDULER, "getRuntimeRegistry", GET_RUNTIME_REGISTRY_CLASS, false); - mv.visitMethodInsn(INVOKESTATIC, initClass, MODULE_STOP_METHOD, INIT_RUNTIME_REGISTRY, false); + mv.visitMethodInsn(INVOKESTATIC, initClass, CURRENT_MODULE_STOP, JvmSignatures.CURRENT_MODULE_STOP, false); } private void startScheduler(int schedulerVarIndex, MethodVisitor mv) { @@ -241,6 +247,12 @@ private void startScheduler(int schedulerVarIndex, MethodVisitor mv) { private void invokeConfigInit(MethodVisitor mv, PackageID packageID) { String configClass = JvmCodeGenUtil.getModuleLevelClassName(packageID, CONFIGURATION_CLASS_NAME); + mv.visitTypeInsn(NEW, HASH_MAP); + mv.visitInsn(DUP); + mv.visitMethodInsn(INVOKESPECIAL, HASH_MAP, JVM_INIT_METHOD, VOID_METHOD_DESC, false); + mv.visitVarInsn(ASTORE, 6); + mv.visitVarInsn(ALOAD, 6); + if (!packageID.isTestPkg) { mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESTATIC, LAUNCH_UTILS, "getConfigurationDetails", GET_CONFIG_DETAILS, @@ -258,10 +270,19 @@ private void invokeConfigInit(MethodVisitor mv, PackageID packageID) { mv.visitVarInsn(ASTORE, configDetailsIndex); mv.visitVarInsn(ALOAD, configDetailsIndex); - mv.visitFieldInsn(GETFIELD, CONFIG_DETAILS, "paths", "[L" + PATH + ";"); + mv.visitFieldInsn(GETFIELD, CONFIG_DETAILS, "paths", GET_PATH); mv.visitVarInsn(ALOAD, configDetailsIndex); - mv.visitFieldInsn(GETFIELD, CONFIG_DETAILS, "configContent", "L" + STRING_VALUE + ";"); + mv.visitFieldInsn(GETFIELD, CONFIG_DETAILS, "configContent", GET_STRING); mv.visitMethodInsn(INVOKESTATIC, configClass, CONFIGURE_INIT, INIT_CONFIG, false); + String moduleInitClass = JvmCodeGenUtil.getModuleLevelClassName(packageID, MODULE_INIT_CLASS_NAME); + mv.visitFieldInsn(GETSTATIC, moduleInitClass, CURRENT_MODULE_VAR_NAME, GET_MODULE); + mv.visitVarInsn(ALOAD, 6); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, configDetailsIndex); + mv.visitFieldInsn(GETFIELD, CONFIG_DETAILS, "paths", GET_PATH); + mv.visitVarInsn(ALOAD, configDetailsIndex); + mv.visitFieldInsn(GETFIELD, CONFIG_DETAILS, "configContent", GET_STRING); + mv.visitMethodInsn(INVOKESTATIC, LAUNCH_UTILS, "initConfigurableVariables", INIT_CONFIGURABLES, false); } private void generateJavaCompatibilityCheck(MethodVisitor mv) { @@ -451,7 +472,7 @@ private void genSubmitToScheduler(String initClass, MethodVisitor mv, boolean is BType anyType = symbolTable.anyType; jvmTypeGen.loadType(mv, anyType); - MethodGenUtils.submitToScheduler(mv, initClass, MAIN_METHOD, asyncDataCollector); + MethodGenUtils.submitToScheduler(mv, this.strandMetadataClass, MAIN_METHOD, asyncDataCollector); storeFuture(indexMap, mv); mv.visitFieldInsn(GETFIELD , FUTURE_VALUE , STRAND, GET_STRAND); mv.visitTypeInsn(NEW, STACK); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/MethodGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/MethodGen.java index cf3003843da8..003e3869bb48 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/MethodGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/MethodGen.java @@ -39,8 +39,8 @@ import org.wso2.ballerinalang.compiler.bir.codegen.internal.LabelGenerator; import org.wso2.ballerinalang.compiler.bir.codegen.interop.ExternalMethodGen; import org.wso2.ballerinalang.compiler.bir.codegen.interop.InteropMethodGen; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JType; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JTypeTags; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JType; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags; import org.wso2.ballerinalang.compiler.bir.codegen.split.JvmConstantsGen; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; import org.wso2.ballerinalang.compiler.bir.model.BIRNode.BIRBasicBlock; @@ -83,12 +83,14 @@ import static org.objectweb.asm.Opcodes.FLOAD; import static org.objectweb.asm.Opcodes.FSTORE; import static org.objectweb.asm.Opcodes.GETFIELD; +import static org.objectweb.asm.Opcodes.GETSTATIC; import static org.objectweb.asm.Opcodes.GOTO; import static org.objectweb.asm.Opcodes.IADD; import static org.objectweb.asm.Opcodes.ICONST_0; import static org.objectweb.asm.Opcodes.ICONST_1; import static org.objectweb.asm.Opcodes.IFEQ; import static org.objectweb.asm.Opcodes.IFGT; +import static org.objectweb.asm.Opcodes.IF_ICMPEQ; import static org.objectweb.asm.Opcodes.ILOAD; import static org.objectweb.asm.Opcodes.INVOKESPECIAL; import static org.objectweb.asm.Opcodes.INVOKESTATIC; @@ -107,8 +109,8 @@ import static org.objectweb.asm.Opcodes.SIPUSH; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil.SCOPE_PREFIX; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil.generateReturnType; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil.getModuleLevelClassName; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil.getMethodDescParams; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil.getModuleLevelClassName; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.ANNOTATIONS_METHOD_PREFIX; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.ERROR_UTILS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.JVM_INIT_METHOD; @@ -116,6 +118,8 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_INIT_CLASS_NAME; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_STARTED; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_START_ATTEMPTED; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.PARENT_MODULE_START_ATTEMPTED; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.NO_OF_DEPENDANT_MODULES; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.OBJECT_SELF_INSTANCE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.STACK; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.STRAND; @@ -280,7 +284,7 @@ public void genJMethodForBFunc(BIRFunction func, ClassWriter cw, BIRPackage modu MethodVisitor mv = cw.visitMethod(access, funcName, desc, null, null); mv.visitCode(); - visitModuleStartFunction(module.packageID, funcName, mv); + visitStartFunction(module.packageID, funcName, mv); Label methodStartLabel = new Label(); mv.visitLabel(methodStartLabel); @@ -302,7 +306,8 @@ public void genJMethodForBFunc(BIRFunction func, ClassWriter cw, BIRPackage modu mv.visitJumpInsn(IFGT, resumeLabel); // set function invocation variable - setFunctionInvocationVar(localVarOffset, mv, invocationVarIndex, invocationCountArgVarIndex); + setFunctionInvocationVar(localVarOffset, mv, invocationVarIndex, invocationCountArgVarIndex, module.packageID, + funcName); // set channel details to strand. setChannelDetailsToStrand(func, localVarOffset, mv, invocationVarIndex); @@ -332,7 +337,7 @@ public void genJMethodForBFunc(BIRFunction func, ClassWriter cw, BIRPackage modu types); JvmErrorGen errorGen = new JvmErrorGen(mv, indexMap, instGen); JvmTerminatorGen termGen = new JvmTerminatorGen(mv, indexMap, labelGen, errorGen, module.packageID, instGen, - jvmPackageGen, jvmTypeGen, jvmCastGen, asyncDataCollector); + jvmPackageGen, jvmTypeGen, jvmCastGen, jvmConstantsGen, asyncDataCollector); mv.visitVarInsn(ILOAD, stateVarIndex); Label yieldLabel = labelGen.getLabel(funcName + "yield"); @@ -387,7 +392,36 @@ public void genJMethodForBFunc(BIRFunction func, ClassWriter cw, BIRPackage modu } private void setFunctionInvocationVar(int localVarOffset, MethodVisitor mv, int invocationVarIndex, - int invocationCountArgVarIndex) { + int invocationCountArgVarIndex, PackageID packageID, String funcName) { + + if (isModuleInitFunction(funcName)) { + String moduleClass = JvmCodeGenUtil.getModuleLevelClassName(packageID, MODULE_INIT_CLASS_NAME); + mv.visitFieldInsn(GETSTATIC, moduleClass, NO_OF_DEPENDANT_MODULES, "I"); + mv.visitInsn(ICONST_1); + mv.visitInsn(IADD); + mv.visitFieldInsn(PUTSTATIC, moduleClass, NO_OF_DEPENDANT_MODULES, "I"); + + Label labelIf = new Label(); + mv.visitFieldInsn(GETSTATIC, moduleClass, NO_OF_DEPENDANT_MODULES, "I"); + mv.visitInsn(ICONST_1); + mv.visitJumpInsn(IF_ICMPEQ, labelIf); + mv.visitInsn(ACONST_NULL); + mv.visitInsn(ARETURN); + mv.visitLabel(labelIf); + } + + if (isModuleStartFunction(funcName)) { + String moduleClass = JvmCodeGenUtil.getModuleLevelClassName(packageID, MODULE_INIT_CLASS_NAME); + mv.visitFieldInsn(GETSTATIC, moduleClass, PARENT_MODULE_START_ATTEMPTED, "Z"); + Label labelIf = new Label(); + mv.visitJumpInsn(IFEQ, labelIf); + mv.visitInsn(ACONST_NULL); + mv.visitInsn(ARETURN); + mv.visitLabel(labelIf); + mv.visitInsn(ICONST_1); + mv.visitFieldInsn(PUTSTATIC, moduleClass, PARENT_MODULE_START_ATTEMPTED, "Z"); + } + if (invocationCountArgVarIndex == -1) { mv.visitVarInsn(ALOAD, localVarOffset); mv.visitInsn(DUP); @@ -417,8 +451,8 @@ private BType getReturnType(BIRFunction func) { return retType; } - private void visitModuleStartFunction(PackageID packageID, String funcName, MethodVisitor mv) { - if (!isModuleStartFunction(funcName)) { + private void visitStartFunction(PackageID packageID, String funcName, MethodVisitor mv) { + if (!isStartFunction(funcName)) { return; } mv.visitInsn(ICONST_1); @@ -428,9 +462,9 @@ private void visitModuleStartFunction(PackageID packageID, String funcName, Meth private void setChannelDetailsToStrand(BIRFunction func, int localVarOffset, MethodVisitor mv, int invocationVarIndex) { - // these channel info is required to notify datachannels, when there is a panic + // this channel info is required to notify data channels when there is a panic // we cannot set this during strand creation, because function call do not have this info. - if (func.workerChannels.length <= 0) { + if (func.workerChannels.length == 0) { return; } mv.visitVarInsn(ALOAD, localVarOffset); @@ -483,79 +517,51 @@ private void genDefaultValue(MethodVisitor mv, BType bType, int index) { } switch (bType.tag) { - case TypeTags.BYTE: - case TypeTags.BOOLEAN: + case TypeTags.BYTE, TypeTags.BOOLEAN -> { mv.visitInsn(ICONST_0); mv.visitVarInsn(ISTORE, index); - break; - case TypeTags.FLOAT: + } + case TypeTags.FLOAT -> { mv.visitInsn(DCONST_0); mv.visitVarInsn(DSTORE, index); - break; - case TypeTags.MAP: - case TypeTags.ARRAY: - case TypeTags.STREAM: - case TypeTags.TABLE: - case TypeTags.ERROR: - case TypeTags.NIL: - case TypeTags.NEVER: - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.OBJECT: - case TypeTags.CHAR_STRING: - case TypeTags.DECIMAL: - case TypeTags.UNION: - case TypeTags.RECORD: - case TypeTags.TUPLE: - case TypeTags.FUTURE: - case TypeTags.JSON: - case TypeTags.INVOKABLE: - case TypeTags.FINITE: - case TypeTags.HANDLE: - case TypeTags.TYPEDESC: - case TypeTags.READONLY: - case TypeTags.REGEXP: + } + case TypeTags.MAP, TypeTags.ARRAY, TypeTags.STREAM, TypeTags.TABLE, TypeTags.ERROR, TypeTags.NIL, + TypeTags.NEVER, TypeTags.ANY, TypeTags.ANYDATA, TypeTags.OBJECT, TypeTags.CHAR_STRING, + TypeTags.DECIMAL, TypeTags.UNION, TypeTags.RECORD, TypeTags.TUPLE, TypeTags.FUTURE, TypeTags.JSON, + TypeTags.INVOKABLE, TypeTags.FINITE, TypeTags.HANDLE, TypeTags.TYPEDESC, TypeTags.READONLY, + TypeTags.REGEXP -> { mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, index); - break; - case JTypeTags.JTYPE: - genJDefaultValue(mv, (JType) bType, index); - break; - default: - throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); + } + case JTypeTags.JTYPE -> genJDefaultValue(mv, (JType) bType, index); + default -> throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); } } private void genJDefaultValue(MethodVisitor mv, JType jType, int index) { switch (jType.jTag) { - case JTypeTags.JBYTE: - case JTypeTags.JCHAR: - case JTypeTags.JSHORT: - case JTypeTags.JINT: - case JTypeTags.JBOOLEAN: + case JTypeTags.JBYTE, JTypeTags.JCHAR, JTypeTags.JSHORT, JTypeTags.JINT, JTypeTags.JBOOLEAN -> { mv.visitInsn(ICONST_0); mv.visitVarInsn(ISTORE, index); - break; - case JTypeTags.JLONG: + } + case JTypeTags.JLONG -> { mv.visitInsn(LCONST_0); mv.visitVarInsn(LSTORE, index); - break; - case JTypeTags.JFLOAT: + } + case JTypeTags.JFLOAT -> { mv.visitInsn(FCONST_0); mv.visitVarInsn(FSTORE, index); - break; - case JTypeTags.JDOUBLE: + } + case JTypeTags.JDOUBLE -> { mv.visitInsn(DCONST_0); mv.visitVarInsn(DSTORE, index); - break; - case JTypeTags.JARRAY: - case JTypeTags.JREF: + } + case JTypeTags.JARRAY, JTypeTags.JREF -> { mv.visitInsn(ACONST_NULL); mv.visitVarInsn(ASTORE, index); - break; - default: - throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + - jType); + } + default -> throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + + jType); } } @@ -663,19 +669,13 @@ private String getFullyQualifiedFuncName(BTypeSymbol funcTypeSymbol, String func } private String getYieldStatusByTerminator(BIRTerminator terminator) { - switch (terminator.kind) { - case WK_SEND: - return "BLOCKED ON WORKER MESSAGE SEND"; - case WK_RECEIVE: - return "BLOCKED ON WORKER MESSAGE RECEIVE"; - case FLUSH: - return "BLOCKED ON WORKER MESSAGE FLUSH"; - case WAIT: - case WAIT_ALL: - return "WAITING"; - default: - return "BLOCKED"; - } + return switch (terminator.kind) { + case WK_SEND -> "BLOCKED ON WORKER MESSAGE SEND"; + case WK_RECEIVE -> "BLOCKED ON WORKER MESSAGE RECEIVE"; + case FLUSH -> "BLOCKED ON WORKER MESSAGE FLUSH"; + case WAIT, WAIT_ALL -> "WAITING"; + default -> "BLOCKED"; + }; } private void pushShort(MethodVisitor mv, int stateVarIndex, int caseIndex) { @@ -705,7 +705,7 @@ private void processTerminator(MethodVisitor mv, BIRFunction func, BIRPackage mo false); } //set module start success to true for $_init class - if (isModuleStartFunction(funcName) && terminator.kind == InstructionKind.RETURN) { + if (isStartFunction(funcName) && terminator.kind == InstructionKind.RETURN) { mv.visitInsn(ICONST_1); mv.visitFieldInsn(PUTSTATIC, JvmCodeGenUtil.getModuleLevelClassName(module.packageID, MODULE_INIT_CLASS_NAME), @@ -719,11 +719,21 @@ private boolean isModuleTestInitFunction(BIRFunction func) { .encodeModuleSpecialFuncName(".")); } - private boolean isModuleStartFunction(String functionName) { + private boolean isStartFunction(String functionName) { return functionName .equals(MethodGenUtils.encodeModuleSpecialFuncName(MethodGenUtils.START_FUNCTION_SUFFIX)); } + private boolean isModuleInitFunction(String functionName) { + return functionName + .equals(MethodGenUtils.encodeModuleSpecialFuncName(JvmConstants.MODULE_INIT_METHOD)); + } + + private boolean isModuleStartFunction(String functionName) { + return functionName + .equals(MethodGenUtils.encodeModuleSpecialFuncName(JvmConstants.MODULE_START_METHOD)); + } + private void genGetFrameOnResumeIndex(int localVarOffset, MethodVisitor mv, String frameName) { mv.visitVarInsn(ALOAD, localVarOffset); mv.visitInsn(DUP); @@ -757,7 +767,7 @@ private void generateFrameClassFieldLoad(List localVars, MethodV } else if (bType.tag == TypeTags.NEVER) { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, GET_OBJECT); mv.visitVarInsn(ASTORE, index); - } else if (types.isAssignable(bType, symbolTable.xmlType)) { + } else if (TypeTags.isXMLTypeTag(bType.tag)) { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, GET_XML); mv.visitVarInsn(ASTORE, index); @@ -776,119 +786,103 @@ private void generateFrameClassFieldLoadByTypeTag(MethodVisitor mv, String frame int index, BType bType) { bType = JvmCodeGenUtil.getImpliedType(bType); switch (bType.tag) { - case TypeTags.BYTE: + case TypeTags.BYTE -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, "I"); mv.visitVarInsn(ISTORE, index); - break; - case TypeTags.FLOAT: + } + case TypeTags.FLOAT -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, "D"); mv.visitVarInsn(DSTORE, index); - break; - case TypeTags.DECIMAL: + } + case TypeTags.DECIMAL -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, GET_BDECIMAL); mv.visitVarInsn(ASTORE, index); - break; - case TypeTags.BOOLEAN: + } + case TypeTags.BOOLEAN -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, "Z"); mv.visitVarInsn(ISTORE, index); - break; - case TypeTags.MAP: - case TypeTags.RECORD: + } + case TypeTags.MAP, TypeTags.RECORD -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, GET_MAP_VALUE); mv.visitVarInsn(ASTORE, index); - break; - case TypeTags.STREAM: + } + case TypeTags.STREAM -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, GET_STREAM_VALUE); mv.visitVarInsn(ASTORE, index); - break; - case TypeTags.TABLE: + } + case TypeTags.TABLE -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, GET_TABLE_VALUE); mv.visitVarInsn(ASTORE, index); - break; - case TypeTags.ARRAY: - case TypeTags.TUPLE: + } + case TypeTags.ARRAY, TypeTags.TUPLE -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, GET_ARRAY_VALUE); mv.visitVarInsn(ASTORE, index); - break; - case TypeTags.OBJECT: + } + case TypeTags.OBJECT -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, GET_BOBJECT); mv.visitVarInsn(ASTORE, index); - break; - case TypeTags.ERROR: + } + case TypeTags.ERROR -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, GET_ERROR_VALUE); mv.visitVarInsn(ASTORE, index); - break; - case TypeTags.FUTURE: + } + case TypeTags.FUTURE -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, GET_FUTURE_VALUE); mv.visitVarInsn(ASTORE, index); - break; - case TypeTags.INVOKABLE: + } + case TypeTags.INVOKABLE -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, GET_FUNCTION_POINTER); mv.visitVarInsn(ASTORE, index); - break; - case TypeTags.TYPEDESC: + } + case TypeTags.TYPEDESC -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, GET_TYPEDESC); mv.visitVarInsn(ASTORE, index); - break; - case TypeTags.NIL: - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.JSON: - case TypeTags.FINITE: - case TypeTags.READONLY: + } + case TypeTags.NIL, TypeTags.ANY, TypeTags.ANYDATA, TypeTags.UNION, + TypeTags.JSON, TypeTags.FINITE, TypeTags.READONLY -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, GET_OBJECT); mv.visitVarInsn(ASTORE, index); - break; - case TypeTags.HANDLE: + } + case TypeTags.HANDLE -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, GET_HANDLE_VALUE); mv.visitVarInsn(ASTORE, index); - break; - case JTypeTags.JTYPE: - generateFrameClassJFieldLoad(localVar, mv, index, frameName); - break; - default: - throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); + } + case JTypeTags.JTYPE -> generateFrameClassJFieldLoad(localVar, mv, index, frameName); + default -> throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); } } private void generateFrameClassJFieldLoad(BIRVariableDcl localVar, MethodVisitor mv, int index, String frameName) { JType jType = (JType) JvmCodeGenUtil.getImpliedType(localVar.type); - switch (jType.jTag) { - case JTypeTags.JBYTE: - case JTypeTags.JCHAR: - case JTypeTags.JSHORT: - case JTypeTags.JINT: + case JTypeTags.JBYTE, JTypeTags.JCHAR, JTypeTags.JSHORT, JTypeTags.JINT -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, "I"); mv.visitVarInsn(ISTORE, index); - break; - case JTypeTags.JLONG: + } + case JTypeTags.JLONG -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, "J"); mv.visitVarInsn(LSTORE, index); - break; - case JTypeTags.JFLOAT: + } + case JTypeTags.JFLOAT -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, "F"); mv.visitVarInsn(FSTORE, index); - break; - case JTypeTags.JDOUBLE: + } + case JTypeTags.JDOUBLE -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, "D"); mv.visitVarInsn(DSTORE, index); - break; - case JTypeTags.JBOOLEAN: + } + case JTypeTags.JBOOLEAN -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, "Z"); mv.visitVarInsn(ISTORE, index); - break; - case JTypeTags.JARRAY: - case JTypeTags.JREF: + } + case JTypeTags.JARRAY, JTypeTags.JREF -> { mv.visitFieldInsn(GETFIELD, frameName, localVar.jvmVarName, InteropMethodGen.getJTypeSignature(jType)); mv.visitVarInsn(ASTORE, index); - break; - default: - throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + - jType); + } + default -> throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + + jType); } } @@ -924,82 +918,71 @@ private void generateFrameClassFieldUpdateByTypeTag(MethodVisitor mv, String fra int index, BType bType) { bType = JvmCodeGenUtil.getImpliedType(bType); switch (bType.tag) { - case TypeTags.BYTE: + case TypeTags.BYTE -> { mv.visitVarInsn(ILOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, "I"); - break; - case TypeTags.FLOAT: + } + case TypeTags.FLOAT -> { mv.visitVarInsn(DLOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, "D"); - break; - case TypeTags.DECIMAL: + } + case TypeTags.DECIMAL -> { mv.visitVarInsn(ALOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, GET_BDECIMAL); - break; - case TypeTags.BOOLEAN: + } + case TypeTags.BOOLEAN -> { mv.visitVarInsn(ILOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, "Z"); - break; - case TypeTags.MAP: - case TypeTags.RECORD: + } + case TypeTags.MAP, TypeTags.RECORD -> { mv.visitVarInsn(ALOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, GET_MAP_VALUE); - break; - case TypeTags.STREAM: + } + case TypeTags.STREAM -> { mv.visitVarInsn(ALOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, GET_STREAM_VALUE); - break; - case TypeTags.TABLE: + } + case TypeTags.TABLE -> { mv.visitVarInsn(ALOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, GET_TABLE_VALUE); - break; - case TypeTags.ARRAY: - case TypeTags.TUPLE: + } + case TypeTags.ARRAY, TypeTags.TUPLE -> { mv.visitVarInsn(ALOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, GET_ARRAY_VALUE); - break; - case TypeTags.ERROR: + } + case TypeTags.ERROR -> { mv.visitVarInsn(ALOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, GET_ERROR_VALUE); - break; - case TypeTags.FUTURE: + } + case TypeTags.FUTURE -> { mv.visitVarInsn(ALOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, GET_FUTURE_VALUE); - break; - case TypeTags.TYPEDESC: + } + case TypeTags.TYPEDESC -> { mv.visitVarInsn(ALOAD, index); mv.visitTypeInsn(CHECKCAST, TYPEDESC_VALUE); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, GET_TYPEDESC); - break; - case TypeTags.OBJECT: + } + case TypeTags.OBJECT -> { mv.visitVarInsn(ALOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, GET_BOBJECT); - break; - case TypeTags.INVOKABLE: + } + case TypeTags.INVOKABLE -> { mv.visitVarInsn(ALOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, GET_FUNCTION_POINTER); - break; - case TypeTags.NIL: - case TypeTags.NEVER: - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.JSON: - case TypeTags.FINITE: - case TypeTags.READONLY: + } + case TypeTags.NIL, TypeTags.NEVER, TypeTags.ANY, TypeTags.ANYDATA, TypeTags.UNION, + TypeTags.JSON, TypeTags.FINITE, TypeTags.READONLY -> { mv.visitVarInsn(ALOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, GET_OBJECT); - break; - case TypeTags.HANDLE: + } + case TypeTags.HANDLE -> { mv.visitVarInsn(ALOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, GET_HANDLE_VALUE); - break; - case JTypeTags.JTYPE: - generateFrameClassJFieldUpdate(localVar, mv, index, frameName); - break; - default: - throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); + } + case JTypeTags.JTYPE -> generateFrameClassJFieldUpdate(localVar, mv, index, frameName); + default -> throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + bType); } } @@ -1007,49 +990,47 @@ private void generateFrameClassJFieldUpdate(BIRVariableDcl localVar, MethodVisit int index, String frameName) { JType jType = (JType) localVar.type; switch (jType.jTag) { - case JTypeTags.JBYTE: + case JTypeTags.JBYTE -> { mv.visitVarInsn(ILOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, "B"); - break; - case JTypeTags.JCHAR: + } + case JTypeTags.JCHAR -> { mv.visitVarInsn(ILOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, "C"); - break; - case JTypeTags.JSHORT: + } + case JTypeTags.JSHORT -> { mv.visitVarInsn(ILOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, "S"); - break; - case JTypeTags.JINT: + } + case JTypeTags.JINT -> { mv.visitVarInsn(ILOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, "I"); - break; - case JTypeTags.JLONG: + } + case JTypeTags.JLONG -> { mv.visitVarInsn(LLOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, "J"); - break; - case JTypeTags.JFLOAT: + } + case JTypeTags.JFLOAT -> { mv.visitVarInsn(FLOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, "F"); - break; - case JTypeTags.JDOUBLE: + } + case JTypeTags.JDOUBLE -> { mv.visitVarInsn(DLOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, "D"); - break; - case JTypeTags.JBOOLEAN: + } + case JTypeTags.JBOOLEAN -> { mv.visitVarInsn(ILOAD, index); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, "Z"); - break; - case JTypeTags.JARRAY: - case JTypeTags.JREF: + } + case JTypeTags.JARRAY, JTypeTags.JREF -> { String classSig = InteropMethodGen.getJTypeSignature(jType); String className = InteropMethodGen.getSignatureForJType(jType); mv.visitVarInsn(ALOAD, index); mv.visitTypeInsn(CHECKCAST, className); mv.visitFieldInsn(PUTFIELD, frameName, localVar.jvmVarName, classSig); - break; - default: - throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + - jType); + } + default -> throw new BLangCompilerException(JvmConstants.TYPE_NOT_SUPPORTED_MESSAGE + + jType); } } @@ -1091,7 +1072,7 @@ private void createLocalVariableTable(BIRFunction func, BIRVarToJVMIndexMap inde // local vars have visible range information if (localVar.kind == VarKind.LOCAL) { if (localVar.startBB != null) { - startLabel = labelGen.getLabel(funcName + SCOPE_PREFIX + localVar.insScope.id); + startLabel = labelGen.getLabel(funcName + SCOPE_PREFIX + localVar.insScope.id()); } if (localVar.endBB != null) { endLabel = labelGen.getLabel(funcName + localVar.endBB.id.value + "beforeTerm"); @@ -1116,7 +1097,7 @@ private boolean isValidArg(BIRVariableDcl localVar) { } private boolean isCompilerAddedVars(String metaVarName) { - return metaVarName != null && !"".equals(metaVarName) && + return metaVarName != null && !metaVarName.isEmpty() && // filter out compiler added vars !((metaVarName.startsWith("$") && metaVarName.endsWith("$")) || (metaVarName.startsWith("$$") && metaVarName.endsWith("$$")) @@ -1135,70 +1116,26 @@ private String getJVMTypeSign(BType bType) { return GET_REGEXP; } - String jvmType; - switch (bType.tag) { - case TypeTags.BYTE: - jvmType = "I"; - break; - case TypeTags.FLOAT: - jvmType = "D"; - break; - case TypeTags.BOOLEAN: - jvmType = "Z"; - break; - case TypeTags.DECIMAL: - jvmType = GET_BDECIMAL; - break; - case TypeTags.MAP: - case TypeTags.RECORD: - jvmType = GET_MAP_VALUE; - break; - case TypeTags.STREAM: - jvmType = GET_STREAM_VALUE; - break; - case TypeTags.TABLE: - jvmType = GET_TABLE_VALUE; - break; - case TypeTags.ARRAY: - case TypeTags.TUPLE: - jvmType = GET_ARRAY_VALUE; - break; - case TypeTags.OBJECT: - jvmType = GET_BOBJECT; - break; - case TypeTags.ERROR: - jvmType = GET_ERROR_VALUE; - break; - case TypeTags.FUTURE: - jvmType = GET_FUTURE_VALUE; - break; - case TypeTags.INVOKABLE: - jvmType = GET_FUNCTION_POINTER; - break; - case TypeTags.HANDLE: - jvmType = GET_HANDLE_VALUE; - break; - case TypeTags.TYPEDESC: - jvmType = GET_TYPEDESC; - break; - case TypeTags.NIL: - case TypeTags.NEVER: - case TypeTags.ANY: - case TypeTags.ANYDATA: - case TypeTags.UNION: - case TypeTags.JSON: - case TypeTags.FINITE: - case TypeTags.READONLY: - jvmType = GET_OBJECT; - break; - case JTypeTags.JTYPE: - jvmType = InteropMethodGen.getJTypeSignature((JType) bType); - break; - default: - throw new BLangCompilerException("JVM code generation is not supported for type " + - bType); - } - - return jvmType; + return switch (bType.tag) { + case TypeTags.BYTE -> "I"; + case TypeTags.FLOAT -> "D"; + case TypeTags.BOOLEAN -> "Z"; + case TypeTags.DECIMAL -> GET_BDECIMAL; + case TypeTags.MAP, TypeTags.RECORD -> GET_MAP_VALUE; + case TypeTags.STREAM -> GET_STREAM_VALUE; + case TypeTags.TABLE -> GET_TABLE_VALUE; + case TypeTags.ARRAY, TypeTags.TUPLE -> GET_ARRAY_VALUE; + case TypeTags.OBJECT -> GET_BOBJECT; + case TypeTags.ERROR -> GET_ERROR_VALUE; + case TypeTags.FUTURE -> GET_FUTURE_VALUE; + case TypeTags.INVOKABLE -> GET_FUNCTION_POINTER; + case TypeTags.HANDLE -> GET_HANDLE_VALUE; + case TypeTags.TYPEDESC -> GET_TYPEDESC; + case TypeTags.NIL, TypeTags.NEVER, TypeTags.ANY, TypeTags.ANYDATA, TypeTags.UNION, + TypeTags.JSON, TypeTags.FINITE, TypeTags.READONLY -> GET_OBJECT; + case JTypeTags.JTYPE -> InteropMethodGen.getJTypeSignature((JType) bType); + default -> throw new BLangCompilerException("JVM code generation is not supported for type " + + bType); + }; } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/MethodGenUtils.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/MethodGenUtils.java index ca5ee11775c4..57aab825ef70 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/MethodGenUtils.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/MethodGenUtils.java @@ -23,7 +23,6 @@ import org.objectweb.asm.MethodVisitor; import org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil; import org.wso2.ballerinalang.compiler.bir.codegen.internal.AsyncDataCollector; -import org.wso2.ballerinalang.compiler.bir.codegen.internal.ScheduleFunctionInfo; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; import org.wso2.ballerinalang.compiler.semantics.model.types.BType; import org.wso2.ballerinalang.compiler.util.Names; @@ -54,8 +53,9 @@ * * @since 2.0.0 */ -public class MethodGenUtils { - static final String FRAMES = "frames"; +public final class MethodGenUtils { + + public static final String FRAMES = "frames"; static final String INIT_FUNCTION_SUFFIX = "."; static final String STOP_FUNCTION_SUFFIX = "."; static final String START_FUNCTION_SUFFIX = "."; @@ -73,17 +73,15 @@ static boolean isModuleInitFunction(BIRNode.BIRFunction func) { return func.name.value.equals(encodeModuleSpecialFuncName(INIT_FUNCTION_SUFFIX)); } - static void submitToScheduler(MethodVisitor mv, String moduleClassName, String workerName, + public static void submitToScheduler(MethodVisitor mv, String strandMetadataClass, String workerName, AsyncDataCollector asyncDataCollector) { - String metaDataVarName = JvmCodeGenUtil.getStrandMetadataVarName(MAIN_METHOD); - asyncDataCollector.getStrandMetadata().putIfAbsent(metaDataVarName, new ScheduleFunctionInfo(MAIN_METHOD)); + String metaDataVarName = JvmCodeGenUtil.setAndGetStrandMetadataVarName(MAIN_METHOD, asyncDataCollector); mv.visitLdcInsn(workerName); - mv.visitFieldInsn(GETSTATIC, moduleClassName, metaDataVarName, GET_STRAND_METADATA); - mv.visitMethodInsn(INVOKEVIRTUAL, SCHEDULER, SCHEDULE_FUNCTION_METHOD, - SCHEDULE_LOCAL, false); + mv.visitFieldInsn(GETSTATIC, strandMetadataClass, metaDataVarName, GET_STRAND_METADATA); + mv.visitMethodInsn(INVOKEVIRTUAL, SCHEDULER, SCHEDULE_FUNCTION_METHOD, SCHEDULE_LOCAL, false); } - static void visitReturn(MethodVisitor mv, String funcName, String className) { + public static void visitReturn(MethodVisitor mv, String funcName, String className) { mv.visitInsn(ARETURN); JvmCodeGenUtil.visitMaxStackForMethod(mv, funcName, className); mv.visitEnd(); @@ -107,7 +105,7 @@ static String calculateLambdaStopFuncName(PackageID id) { String funcName; if (moduleName.equals(ENCODED_DOT_CHARACTER)) { funcName = ".." + funcSuffix; - } else if (version.equals("")) { + } else if (version.isEmpty()) { funcName = moduleName + "." + funcSuffix; } else { funcName = moduleName + ":" + version + "." + funcSuffix; @@ -120,7 +118,7 @@ static String calculateLambdaStopFuncName(PackageID id) { return LAMBDA_PREFIX + Utils.encodeFunctionIdentifier(funcName); } - static void callSetDaemonStrand(MethodVisitor mv) { + public static void callSetDaemonStrand(MethodVisitor mv) { // set daemon strand mv.visitVarInsn(ALOAD, 0); mv.visitInsn(ICONST_0); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/ModuleStopMethodGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/ModuleStopMethodGen.java index 9e93b87a7467..7f9064b5d3f5 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/ModuleStopMethodGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/methodgen/ModuleStopMethodGen.java @@ -27,47 +27,45 @@ import org.wso2.ballerinalang.compiler.bir.codegen.JvmTypeGen; import org.wso2.ballerinalang.compiler.bir.codegen.internal.AsyncDataCollector; import org.wso2.ballerinalang.compiler.bir.codegen.internal.BIRVarToJVMIndexMap; +import org.wso2.ballerinalang.compiler.bir.codegen.split.JvmConstantsGen; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; -import org.wso2.ballerinalang.compiler.semantics.model.SymbolTable; import org.wso2.ballerinalang.compiler.semantics.model.types.BNilType; -import java.util.List; +import java.util.Set; -import static org.objectweb.asm.Opcodes.AALOAD; -import static org.objectweb.asm.Opcodes.AASTORE; import static org.objectweb.asm.Opcodes.ACC_STATIC; import static org.objectweb.asm.Opcodes.ACONST_NULL; import static org.objectweb.asm.Opcodes.ALOAD; import static org.objectweb.asm.Opcodes.ANEWARRAY; import static org.objectweb.asm.Opcodes.ASTORE; import static org.objectweb.asm.Opcodes.BIPUSH; -import static org.objectweb.asm.Opcodes.CHECKCAST; import static org.objectweb.asm.Opcodes.DUP; import static org.objectweb.asm.Opcodes.GETFIELD; import static org.objectweb.asm.Opcodes.GETSTATIC; import static org.objectweb.asm.Opcodes.GOTO; -import static org.objectweb.asm.Opcodes.ICONST_0; import static org.objectweb.asm.Opcodes.ICONST_1; import static org.objectweb.asm.Opcodes.IFEQ; +import static org.objectweb.asm.Opcodes.IFLE; import static org.objectweb.asm.Opcodes.IFNULL; import static org.objectweb.asm.Opcodes.INVOKESPECIAL; import static org.objectweb.asm.Opcodes.INVOKESTATIC; import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL; +import static org.objectweb.asm.Opcodes.ISUB; import static org.objectweb.asm.Opcodes.NEW; import static org.objectweb.asm.Opcodes.PUTFIELD; +import static org.objectweb.asm.Opcodes.PUTSTATIC; import static org.objectweb.asm.Opcodes.RETURN; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.FUTURE_VALUE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.HANDLE_RETURNED_ERROR_METHOD_WITHOUT_EXIT; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.HANDLE_STOP_PANIC_METHOD; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.JVM_INIT_METHOD; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.LAMBDA_PREFIX; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_INIT_CLASS_NAME; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_STARTED; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_START_ATTEMPTED; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.MODULE_STOP_METHOD; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.NO_OF_DEPENDANT_MODULES; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.OBJECT; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.PANIC_FIELD; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.RUNTIME_REGISTRY_CLASS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.RUNTIME_UTILS; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.SCHEDULER; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.SCHEDULER_START_METHOD; @@ -79,9 +77,7 @@ import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.GET_THROWABLE; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.HANDLE_ERROR_RETURN; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.HANDLE_STOP_PANIC; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.INIT_RUNTIME_REGISTRY; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.LAMBDA_STOP_DYNAMIC; -import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.SET_STRAND; +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.MODULE_STOP; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.STACK_FRAMES; import static org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures.VOID_METHOD_DESC; @@ -91,119 +87,53 @@ * @since 2.0.0 */ public class ModuleStopMethodGen { - public static final String SCHEDULER_VAR = "schedulerVar"; public static final String FUTURE_VAR = "futureVar"; public static final String ARR_VAR = "arrVar"; - private final SymbolTable symbolTable; private final BIRVarToJVMIndexMap indexMap; private final JvmTypeGen jvmTypeGen; + private final String strandMetadataClass; - public ModuleStopMethodGen(SymbolTable symbolTable, JvmTypeGen jvmTypeGen) { - this.symbolTable = symbolTable; + public ModuleStopMethodGen(JvmTypeGen jvmTypeGen, JvmConstantsGen jvmConstantsGen) { indexMap = new BIRVarToJVMIndexMap(1); this.jvmTypeGen = jvmTypeGen; + this.strandMetadataClass = jvmConstantsGen.getStrandMetadataConstantsClass(); } public void generateExecutionStopMethod(ClassWriter cw, String initClass, BIRNode.BIRPackage module, - List imprtMods, AsyncDataCollector asyncDataCollector) { + AsyncDataCollector asyncDataCollector, Set immediateImports) { MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC + ACC_STATIC, MODULE_STOP_METHOD, - INIT_RUNTIME_REGISTRY, null, null); + MODULE_STOP, null, null); mv.visitCode(); - - int schedulerIndex = indexMap.addIfNotExists(SCHEDULER_VAR, symbolTable.anyType); - // Create a scheduler. A new scheduler is used here, to make the stop function to not to - // depend/wait on whatever is being running on the background. eg: a busy loop in the main. - mv.visitTypeInsn(NEW, SCHEDULER); - mv.visitInsn(DUP); - mv.visitInsn(ICONST_1); - mv.visitInsn(ICONST_0); - mv.visitMethodInsn(INVOKESPECIAL, SCHEDULER, JVM_INIT_METHOD, "(IZ)V", false); - mv.visitVarInsn(ASTORE, schedulerIndex); - String moduleInitClass = getModuleInitClassName(module.packageID); String fullFuncName = MethodGenUtils.calculateLambdaStopFuncName(module.packageID); - String lambdaName = generateStopDynamicLambdaBody(cw, initClass); - indexMap.addIfNotExists(FUTURE_VAR, symbolTable.anyType); - scheduleStopLambda(mv, initClass, fullFuncName, moduleInitClass, asyncDataCollector); - int i = imprtMods.size() - 1; - while (i >= 0) { - PackageID id = imprtMods.get(i); - i -= 1; - fullFuncName = MethodGenUtils.calculateLambdaStopFuncName(id); - moduleInitClass = getModuleInitClassName(id); - scheduleStopLambda(mv, initClass, fullFuncName, moduleInitClass, asyncDataCollector); - } - moduleInitClass = getModuleInitClassName(module.packageID); - generateCallStopDynamicLambda(mv, lambdaName, moduleInitClass, asyncDataCollector); - mv.visitInsn(RETURN); - JvmCodeGenUtil.visitMaxStackForMethod(mv, MODULE_STOP_METHOD, initClass); - mv.visitEnd(); - } - - private String generateStopDynamicLambdaBody(ClassWriter cw, String initClass) { - String lambdaName = LAMBDA_PREFIX + "stopdynamic"; - MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC + ACC_STATIC, lambdaName, LAMBDA_STOP_DYNAMIC, null, null); - mv.visitCode(); - MethodGenUtils.callSetDaemonStrand(mv); - generateCallSchedulerStopDynamicListeners(mv, lambdaName, initClass); - return lambdaName; - } - - private void generateCallStopDynamicLambda(MethodVisitor mv, String lambdaName, String moduleInitClass, - AsyncDataCollector asyncDataCollector) { - addRuntimeRegistryAsParameter(mv); - generateMethodBody(mv, moduleInitClass, lambdaName, asyncDataCollector); + mv.visitFieldInsn(GETSTATIC, initClass, NO_OF_DEPENDANT_MODULES, "I"); + mv.visitInsn(ICONST_1); + mv.visitInsn(ISUB); + mv.visitFieldInsn(PUTSTATIC, initClass, NO_OF_DEPENDANT_MODULES, "I"); - // handle any runtime errors - int futureIndex = indexMap.get(FUTURE_VAR); + mv.visitFieldInsn(GETSTATIC, initClass, NO_OF_DEPENDANT_MODULES, "I"); Label labelIf = new Label(); - mv.visitVarInsn(ALOAD, futureIndex); - mv.visitFieldInsn(GETFIELD, FUTURE_VALUE, PANIC_FIELD, GET_THROWABLE); - mv.visitJumpInsn(IFNULL, labelIf); - - mv.visitVarInsn(ALOAD, futureIndex); - mv.visitFieldInsn(GETFIELD, FUTURE_VALUE, PANIC_FIELD, GET_THROWABLE); - mv.visitMethodInsn(INVOKESTATIC, RUNTIME_UTILS, HANDLE_STOP_PANIC_METHOD, HANDLE_STOP_PANIC, - false); - Label labelJump = new Label(); - mv.visitJumpInsn(GOTO, labelJump); + mv.visitJumpInsn(IFLE, labelIf); + mv.visitInsn(RETURN); mv.visitLabel(labelIf); - genHandleErrorReturn(mv, indexMap); - mv.visitLabel(labelJump); - } - private void generateCallSchedulerStopDynamicListeners(MethodVisitor mv, String lambdaName, String initClass) { - mv.visitVarInsn(ALOAD, 0); - mv.visitInsn(ICONST_1); - mv.visitInsn(AALOAD); - mv.visitTypeInsn(CHECKCAST, RUNTIME_REGISTRY_CLASS); - mv.visitVarInsn(ALOAD, 0); - mv.visitInsn(ICONST_0); - mv.visitInsn(AALOAD); - mv.visitTypeInsn(CHECKCAST, STRAND_CLASS); - mv.visitMethodInsn(INVOKEVIRTUAL, RUNTIME_REGISTRY_CLASS, "gracefulStop", - SET_STRAND, false); - mv.visitInsn(ACONST_NULL); - MethodGenUtils.visitReturn(mv, lambdaName, initClass); - } + scheduleStopLambda(mv, initClass, fullFuncName, moduleInitClass, asyncDataCollector); + for (PackageID immediateImport : immediateImports) { + moduleInitClass = getModuleInitClassName(immediateImport); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitMethodInsn(INVOKESTATIC, moduleInitClass, MODULE_STOP_METHOD, MODULE_STOP, false); + } - private void addRuntimeRegistryAsParameter(MethodVisitor mv) { - int arrIndex = indexMap.addIfNotExists(ARR_VAR, symbolTable.anyType); - mv.visitIntInsn(BIPUSH, 2); - mv.visitTypeInsn(ANEWARRAY, OBJECT); - mv.visitVarInsn(ASTORE, arrIndex); - mv.visitVarInsn(ALOAD, arrIndex); - mv.visitInsn(ICONST_1); - mv.visitVarInsn(ALOAD, 0); - mv.visitInsn(AASTORE); - mv.visitVarInsn(ALOAD, indexMap.get(SCHEDULER_VAR)); - mv.visitVarInsn(ALOAD, arrIndex); + mv.visitInsn(RETURN); + JvmCodeGenUtil.visitMaxStackForMethod(mv, MODULE_STOP_METHOD, initClass); + mv.visitEnd(); } private void scheduleStopLambda(MethodVisitor mv, String initClass, String stopFuncName, String moduleClass, AsyncDataCollector asyncDataCollector) { Label labelIf = createIfLabel(mv, moduleClass); - mv.visitVarInsn(ALOAD, indexMap.get(SCHEDULER_VAR)); + mv.visitVarInsn(ALOAD, 0); mv.visitIntInsn(BIPUSH, 1); mv.visitTypeInsn(ANEWARRAY, OBJECT); @@ -222,45 +152,39 @@ private void generateMethodBody(MethodVisitor mv, String initClass, String stopF // no parent strand mv.visitInsn(ACONST_NULL); jvmTypeGen.loadType(mv, new BNilType()); - MethodGenUtils.submitToScheduler(mv, initClass, "stop", asyncDataCollector); - int futureIndex = indexMap.get(FUTURE_VAR); - mv.visitVarInsn(ASTORE, futureIndex); - - mv.visitVarInsn(ALOAD, futureIndex); + MethodGenUtils.submitToScheduler(mv, this.strandMetadataClass, "stop", asyncDataCollector); + mv.visitVarInsn(ASTORE, 1); + mv.visitVarInsn(ALOAD, 1); mv.visitFieldInsn(GETFIELD, FUTURE_VALUE, STRAND, GET_STRAND); mv.visitTypeInsn(NEW, STACK); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, STACK, JVM_INIT_METHOD, VOID_METHOD_DESC, false); mv.visitFieldInsn(PUTFIELD, STRAND_CLASS, MethodGenUtils.FRAMES, STACK_FRAMES); - int schedulerIndex = indexMap.get(SCHEDULER_VAR); - mv.visitVarInsn(ALOAD, schedulerIndex); + mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKEVIRTUAL, SCHEDULER, SCHEDULER_START_METHOD, VOID_METHOD_DESC, false); - } - private void genHandleRuntimeErrors(MethodVisitor mv, String moduleClass, Label labelJump) { - int futureIndex = indexMap.get(FUTURE_VAR); - mv.visitVarInsn(ALOAD, futureIndex); + mv.visitVarInsn(ALOAD, 1); mv.visitFieldInsn(GETFIELD, FUTURE_VALUE, PANIC_FIELD, GET_THROWABLE); Label labelIf = new Label(); mv.visitJumpInsn(IFNULL, labelIf); mv.visitFieldInsn(GETSTATIC, moduleClass, MODULE_STARTED, "Z"); mv.visitJumpInsn(IFEQ, labelIf); - mv.visitVarInsn(ALOAD, futureIndex); + mv.visitVarInsn(ALOAD, 1); mv.visitFieldInsn(GETFIELD, FUTURE_VALUE, PANIC_FIELD, GET_THROWABLE); mv.visitMethodInsn(INVOKESTATIC, RUNTIME_UTILS, HANDLE_STOP_PANIC_METHOD, HANDLE_STOP_PANIC, false); mv.visitJumpInsn(GOTO, labelJump); mv.visitLabel(labelIf); - genHandleErrorReturn(mv, indexMap); + genHandleErrorReturn(mv); mv.visitLabel(labelJump); } - private void genHandleErrorReturn(MethodVisitor mv, BIRVarToJVMIndexMap indexMap) { - mv.visitVarInsn(ALOAD, indexMap.get(FUTURE_VAR)); + private void genHandleErrorReturn(MethodVisitor mv) { + mv.visitVarInsn(ALOAD, 1); mv.visitFieldInsn(GETFIELD , FUTURE_VALUE, "result", GET_OBJECT); mv.visitMethodInsn(INVOKESTATIC , RUNTIME_UTILS , HANDLE_RETURNED_ERROR_METHOD_WITHOUT_EXIT, HANDLE_ERROR_RETURN, false); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/BIRFunctionWrapper.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/BIRFunctionWrapper.java similarity index 53% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/BIRFunctionWrapper.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/BIRFunctionWrapper.java index 56ea5b1e2fed..55f95e360f48 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/BIRFunctionWrapper.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/BIRFunctionWrapper.java @@ -15,28 +15,22 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; import org.ballerinalang.model.elements.PackageID; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; /** - * A wrapper used with JInterop to wrap BFuntions with JFunc description and data. + * A wrapper used with JInterop to wrap Ballerina Functions with JFunc description and data. * * @since 1.2.0 + * + * @param packageID Package ID + * @param func BIR function + * @param fullQualifiedClassName full qualified class name + * @param jvmMethodDescription JVM method description */ -public class BIRFunctionWrapper { - - public final PackageID packageID; - public final BIRNode.BIRFunction func; - public final String fullQualifiedClassName; - public final String jvmMethodDescription; +public record BIRFunctionWrapper(PackageID packageID, BIRNode.BIRFunction func, String fullQualifiedClassName, + String jvmMethodDescription) { - public BIRFunctionWrapper(PackageID packageID, BIRNode.BIRFunction func, - String fullQualifiedClassName, String jvmMethodDescription) { - this.packageID = packageID; - this.func = func; - this.fullQualifiedClassName = fullQualifiedClassName; - this.jvmMethodDescription = jvmMethodDescription; - } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/CatchIns.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/CatchIns.java similarity index 93% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/CatchIns.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/CatchIns.java index 104fe7cc9495..f4bf32bae5f3 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/CatchIns.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/CatchIns.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; import org.wso2.ballerinalang.compiler.bir.model.BIRTerminator; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JBIRFunction.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JBIRFunction.java similarity index 96% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JBIRFunction.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JBIRFunction.java index ab8c5b19cd04..537d38e69763 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JBIRFunction.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JBIRFunction.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JCast.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JCast.java similarity index 90% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JCast.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JCast.java index 0ffded59f277..5fefdd261e87 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JCast.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JCast.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; import io.ballerina.tools.diagnostics.Location; import org.wso2.ballerinalang.compiler.bir.model.BIROperand; @@ -32,10 +32,10 @@ public class JCast extends JInstruction { public BIROperand rhsOp; public BType targetType; - JCast(Location pos) { + public JCast(Location pos) { super(pos); - jKind = JInsKind.JCAST; + jKind = JInsKind.J_CAST; } @Override diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JErrorEntry.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JErrorEntry.java similarity index 95% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JErrorEntry.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JErrorEntry.java index e314bd7dbe5a..78a3bcba87c0 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JErrorEntry.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JErrorEntry.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; import org.wso2.ballerinalang.compiler.bir.model.BIROperand; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JFieldBIRFunction.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JFieldBIRFunction.java similarity index 94% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JFieldBIRFunction.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JFieldBIRFunction.java index 349c07939ac4..aac0c0fe27b5 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JFieldBIRFunction.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JFieldBIRFunction.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; /** * A wrapper @BIRFunction to keep java field with bir function data. diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JIConstructorCall.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JIConstructorCall.java similarity index 86% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JIConstructorCall.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JIConstructorCall.java index f02f1d3e6676..f72d810ed0b4 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JIConstructorCall.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JIConstructorCall.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; import io.ballerina.tools.diagnostics.Location; import org.wso2.ballerinalang.compiler.bir.model.BIROperand; @@ -37,10 +37,10 @@ public class JIConstructorCall extends JTerminator { public String jClassName; public String jMethodVMSig; public String name; - boolean varArgExist; - JType varArgType; + public boolean varArgExist; + public JType varArgType; - JIConstructorCall(Location pos) { + public JIConstructorCall(Location pos) { super(pos); this.jTermKind = JTermKind.JI_CONSTRUCTOR_CALL; @@ -61,8 +61,4 @@ public void setRhsOperands(BIROperand[] operands) { this.args = List.of(operands); } - @Override - public BIRBasicBlock[] getNextBasicBlocks() { - return new BIRBasicBlock[0]; - } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JIMethodCLICall.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JIMethodCLICall.java similarity index 96% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JIMethodCLICall.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JIMethodCLICall.java index 840bc7ee669f..64ff85ff715a 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JIMethodCLICall.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JIMethodCLICall.java @@ -16,7 +16,7 @@ * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; import io.ballerina.tools.diagnostics.Location; import org.wso2.ballerinalang.compiler.bir.model.BIROperand; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JIMethodCall.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JIMethodCall.java similarity index 91% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JIMethodCall.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JIMethodCall.java index 8a7d2da85f9f..fddbba24ae82 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JIMethodCall.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JIMethodCall.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; import io.ballerina.tools.diagnostics.Location; import org.wso2.ballerinalang.compiler.bir.model.BIROperand; @@ -63,8 +63,4 @@ public void setRhsOperands(BIROperand[] operands) { this.args = List.of(operands); } - @Override - public BIRBasicBlock[] getNextBasicBlocks() { - return new BIRBasicBlock[0]; - } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JInsKind.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JInsKind.java similarity index 72% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JInsKind.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JInsKind.java index aaf8fdf07672..75b4fc0de5cf 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JInsKind.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JInsKind.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; /** * An enum to model the JInstruction kind. @@ -23,20 +23,8 @@ * @since 1.2.0 */ public enum JInsKind { - JCAST((byte) 1), - CALL((byte) 2), - LARGE_ARRAY((byte) 3), - LARGE_MAP((byte) 4); - - byte value; - - JInsKind(byte value) { - - this.value = value; - } - - public byte getValue() { - - return this.value; - } + J_CAST(), + CALL(), + LARGE_ARRAY(), + LARGE_MAP() } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JInstruction.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JInstruction.java similarity index 96% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JInstruction.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JInstruction.java index 8ad80701ee67..89ce3bd421d2 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JInstruction.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JInstruction.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; import io.ballerina.tools.diagnostics.Location; import org.wso2.ballerinalang.compiler.bir.model.BIRNonTerminator; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JLargeArrayInstruction.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JLargeArrayInstruction.java similarity index 97% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JLargeArrayInstruction.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JLargeArrayInstruction.java index c49b2885326d..94fc56ae626f 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JLargeArrayInstruction.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JLargeArrayInstruction.java @@ -16,7 +16,7 @@ * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; import io.ballerina.tools.diagnostics.Location; import org.wso2.ballerinalang.compiler.bir.model.BIROperand; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JLargeMapInstruction.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JLargeMapInstruction.java similarity index 96% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JLargeMapInstruction.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JLargeMapInstruction.java index 2a043e14d5fd..18c7eb72839d 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JLargeMapInstruction.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JLargeMapInstruction.java @@ -16,7 +16,7 @@ * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; import io.ballerina.tools.diagnostics.Location; import org.wso2.ballerinalang.compiler.bir.model.BIROperand; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethod.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JMethod.java similarity index 64% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethod.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JMethod.java index 7437d6f2e958..ef718ee89cc6 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethod.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JMethod.java @@ -15,13 +15,11 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; import io.ballerina.runtime.api.Environment; -import io.ballerina.runtime.api.PredefinedTypes; -import io.ballerina.runtime.api.creators.TypeCreator; -import io.ballerina.runtime.api.creators.ValueCreator; -import io.ballerina.runtime.api.values.BArray; +import org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil; +import org.wso2.ballerinalang.compiler.bir.codegen.exceptions.JInteropException; import org.wso2.ballerinalang.compiler.semantics.model.types.BType; import java.lang.reflect.Constructor; @@ -39,13 +37,13 @@ * * @since 1.2.0 */ -class JMethod { +public class JMethod { - static final JMethod NO_SUCH_METHOD = new JMethod(null, null, null); + public static final JMethod NO_SUCH_METHOD = new JMethod(null, null, null); public static final String BAL_ENV_CANONICAL_NAME = Environment.class.getCanonicalName(); - JMethodKind kind; - private Executable method; + public JMethodKind kind; + private final Executable method; private BType receiverType; public boolean hasBundledPathParams = false; public boolean hasBundledFunctionParams = false; @@ -57,33 +55,33 @@ private JMethod(JMethodKind kind, Executable executable, BType receiverType) { this.receiverType = receiverType; } - static JMethod build(JMethodKind kind, Executable executable, BType receiverType) { + public static JMethod build(JMethodKind kind, Executable executable, BType receiverType) { return new JMethod(kind, executable, receiverType); } - String getClassName() { + public String getClassName() { return method.getDeclaringClass().getName(); } - boolean isDeclaringClassInterface() { + public boolean isDeclaringClassInterface() { return this.method.getDeclaringClass().isInterface(); } - boolean isStatic() { + public boolean isStatic() { return Modifier.isStatic(method.getModifiers()); } - boolean isInstanceMethod() { + public boolean isInstanceMethod() { return !isStatic() && !(method instanceof Constructor); } - String getName() { + public String getName() { if (kind == JMethodKind.CONSTRUCTOR) { return JVM_INIT_METHOD; @@ -92,30 +90,30 @@ String getName() { } } - JMethodKind getKind() { + public JMethodKind getKind() { return kind; } - Executable getMethod() { + public Executable getMethod() { return method; } - String getSignature() { + public String getSignature() { if (kind == JMethodKind.CONSTRUCTOR) { - return JInterop.getMethodSig(void.class, method.getParameterTypes()); + return JvmCodeGenUtil.getMethodSig(void.class, method.getParameterTypes()); } else { - return JInterop.getMethodSig(getReturnType(), method.getParameterTypes()); + return JvmCodeGenUtil.getMethodSig(getReturnType(), method.getParameterTypes()); } } - Class[] getParamTypes() { + public Class[] getParamTypes() { return method.getParameterTypes(); } - Class getReturnType() { + public Class getReturnType() { if (kind == JMethodKind.CONSTRUCTOR) { return method.getDeclaringClass(); @@ -132,29 +130,7 @@ public void setReceiverType(BType receiverType) { this.receiverType = receiverType; } - BArray getExceptionTypes(ClassLoader classLoader) { - - List checkedExceptions = new ArrayList<>(); - try { - Class runtimeException = classLoader.loadClass(RuntimeException.class.getCanonicalName()); - for (Class exceptionType : method.getExceptionTypes()) { - if (!runtimeException.isAssignableFrom(exceptionType)) { - checkedExceptions.add(exceptionType); - } - } - } catch (ClassNotFoundException | NoClassDefFoundError e) { - throw new JInteropException(CLASS_NOT_FOUND, e.getMessage(), e); - } - - BArray arrayValue = ValueCreator.createArrayValue(TypeCreator.createArrayType(PredefinedTypes.TYPE_STRING)); - int i = 0; - for (Class exceptionType : checkedExceptions) { - arrayValue.add(i++, exceptionType.getName().replace(".", "/")); - } - return arrayValue; - } - - Class[] getExceptionTypes() { + public Class[] getExceptionTypes() { List> checkedExceptions = new ArrayList<>(); try { diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethodBIRFunction.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JMethodBIRFunction.java similarity index 91% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethodBIRFunction.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JMethodBIRFunction.java index 46afbc30f91e..d7a86dfe24f7 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethodBIRFunction.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JMethodBIRFunction.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; /** * A wrapper @BIRFunction to keep java function with bir function data. @@ -24,7 +24,7 @@ */ public class JMethodBIRFunction extends JBIRFunction { - JMethod jMethod; + public JMethod jMethod; public JMethodBIRFunction(BIRFunction birFunction, JMethod jMethod) { super(birFunction); diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethodCallInstruction.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JMethodCallInstruction.java similarity index 96% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethodCallInstruction.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JMethodCallInstruction.java index 4e1c7dfc253c..db30b95ed3d7 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethodCallInstruction.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JMethodCallInstruction.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; import io.ballerina.tools.diagnostics.Location; import org.wso2.ballerinalang.compiler.bir.model.BIROperand; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethodKind.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JMethodKind.java similarity index 68% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethodKind.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JMethodKind.java index 4333ccb25291..c64ef6ca2aad 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JMethodKind.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JMethodKind.java @@ -15,37 +15,34 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; /** * This enum is used to indicate whether the given Java method is a static method or an instance or a constructor. * * @since 1.2.0 */ -enum JMethodKind { +public enum JMethodKind { METHOD("method"), CONSTRUCTOR("constructor"); - private String strValue; + private final String strValue; JMethodKind(String strValue) { this.strValue = strValue; } - static JMethodKind getKind(String value) { + public static JMethodKind getKind(String value) { - switch (value) { - case "method": - return METHOD; - case "constructor": - return CONSTRUCTOR; - default: - throw new IllegalStateException("Unknown Java method modifier '" + value + "'"); - } + return switch (value) { + case "method" -> METHOD; + case "constructor" -> CONSTRUCTOR; + default -> throw new IllegalStateException("Unknown Java method modifier '" + value + "'"); + }; } - String getStringValue() { + public String getStringValue() { return this.strValue; } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JTermKind.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JTermKind.java similarity index 66% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JTermKind.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JTermKind.java index 1e53340abf98..04fa18e7c328 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JTermKind.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JTermKind.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; /** * Java terminator kinds. @@ -23,21 +23,14 @@ * @since 1.2.0 */ public enum JTermKind { - J_METHOD_CALL((byte) 1), - JI_METHOD_CALL((byte) 2), - JI_CONSTRUCTOR_CALL((byte) 3), - J_INTERNAL_METHOD_CALL((byte) 4), - JI_METHOD_CLI_CALL((byte) 5); + J_METHOD_CALL(), + JI_METHOD_CALL(), + JI_CONSTRUCTOR_CALL(), + J_INTERNAL_METHOD_CALL(), + JI_METHOD_CLI_CALL(); - private final byte termKind; + JTermKind() { - JTermKind(byte termKind) { - - this.termKind = termKind; } - public byte getTermKind() { - - return this.termKind; - } } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JTerminator.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JTerminator.java similarity index 96% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JTerminator.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JTerminator.java index 39de4ca7fc25..f71db45f3c9a 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JTerminator.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JTerminator.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; import io.ballerina.tools.diagnostics.Location; import org.wso2.ballerinalang.compiler.bir.model.BIROperand; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JType.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JType.java new file mode 100644 index 000000000000..484a50402b69 --- /dev/null +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JType.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. 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 org.wso2.ballerinalang.compiler.bir.codegen.model; + +import org.wso2.ballerinalang.compiler.semantics.model.types.BType; + +import static org.wso2.ballerinalang.compiler.bir.codegen.JvmConstants.OBJECT; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JARRAY; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JBOOLEAN; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JBYTE; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JCHAR; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JDOUBLE; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JFLOAT; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JINT; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JLONG; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JREF; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JSHORT; +import static org.wso2.ballerinalang.compiler.bir.codegen.model.JTypeTags.JVOID; +import static org.wso2.ballerinalang.compiler.util.TypeTags.BOOLEAN; +import static org.wso2.ballerinalang.compiler.util.TypeTags.BYTE; +import static org.wso2.ballerinalang.compiler.util.TypeTags.FLOAT; +import static org.wso2.ballerinalang.compiler.util.TypeTags.INT; + +/** + * Interop representation of Java types. + * + * @since 1.2.0 + */ +public class JType extends BType { + + private static final String JBYTE_KIND = "byte"; + private static final String JCHAR_KIND = "char"; + private static final String JSHORT_KIND = "short"; + private static final String JINT_KIND = "int"; + private static final String JLONG_KIND = "long"; + private static final String JFLOAT_KIND = "float"; + private static final String JDOUBLE_KIND = "double"; + private static final String JBOOLEAN_KIND = "boolean"; + private static final String JVOID_KIND = "void"; + public static final JType J_VOID = new JType(JVOID); + private static final JType J_BYTE = new JType(JBYTE); + private static final JType J_CHAR = new JType(JCHAR); + private static final JType J_SHORT = new JType(JSHORT); + private static final JType J_INT = new JType(JINT); + private static final JType J_LONG = new JType(JLONG); + private static final JType J_FLOAT = new JType(JFLOAT); + private static final JType J_DOUBLE = new JType(JDOUBLE); + private static final JType J_BOOLEAN = new JType(JBOOLEAN); + public int jTag; + + JType(int jTag) { + + super(JTypeTags.JTYPE, null); + this.jTag = jTag; + } + + public static JType getJTypeFromTypeName(String typeName) { + + return switch (typeName) { + case JBYTE_KIND -> J_BYTE; + case JCHAR_KIND -> J_CHAR; + case JSHORT_KIND -> J_SHORT; + case JINT_KIND -> J_INT; + case JLONG_KIND -> J_LONG; + case JFLOAT_KIND -> J_FLOAT; + case JDOUBLE_KIND -> J_DOUBLE; + case JBOOLEAN_KIND -> J_BOOLEAN; + case JVOID_KIND -> J_VOID; + default -> new JRefType(typeName.replace('.', '/')); + }; + } + + public static JType getJTypeForPrimitive(String typeName) { + + return switch (typeName) { + case JBYTE_KIND -> J_BYTE; + case JCHAR_KIND -> J_CHAR; + case JSHORT_KIND -> J_SHORT; + case JINT_KIND -> J_INT; + case JLONG_KIND -> J_LONG; + case JFLOAT_KIND -> J_FLOAT; + case JDOUBLE_KIND -> J_DOUBLE; + case JBOOLEAN_KIND -> J_BOOLEAN; + case JVOID_KIND -> J_VOID; + default -> throw new IllegalArgumentException("The Java " + typeName + " type is not yet supported."); + }; + } + + public static JArrayType getJArrayTypeFromTypeName(String typeName, byte dimensions) { + + JArrayType arrayType = new JArrayType(getJTypeFromTypeName(typeName)); + int i = 1; + while (i < ((int) dimensions)) { + arrayType = new JArrayType(arrayType); + i += 1; + } + + return arrayType; + } + + public static JType getJTypeForBType(BType type) { + return switch (type.tag) { + case INT -> J_LONG; + case BYTE -> J_INT; + case BOOLEAN -> J_BOOLEAN; + case FLOAT -> J_FLOAT; + default -> new JRefType(OBJECT); + }; + } + + /** + * Java array type. + * + * @since 1.2.0 + */ + public static class JArrayType extends JType { + + public JType elementType; + + public JArrayType(JType elementType) { + super(JARRAY); + this.elementType = elementType; + } + } + + /** + * Java referenced type. + * + * @since 1.2.0 + */ + public static class JRefType extends JType { + + public String typeValue; + public boolean isInterface = false; + public boolean isArray = false; + + public JRefType(String typeValue) { + super(JREF); + this.typeValue = typeValue; + } + } +} diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JTypeTags.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JTypeTags.java similarity index 93% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JTypeTags.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JTypeTags.java index 5d34a79af864..085fa07495a8 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JTypeTags.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JTypeTags.java @@ -15,14 +15,14 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; /** * Type tag values for JTypes. * * @since 1.2.0 */ -public class JTypeTags { +public final class JTypeTags { public static final int JBYTE = 1; public static final int JCHAR = 2; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JavaField.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JavaField.java similarity index 65% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JavaField.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JavaField.java index 021f00ab69f7..497d4a6e484d 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JavaField.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JavaField.java @@ -15,7 +15,10 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; + +import org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil; +import org.wso2.ballerinalang.compiler.bir.codegen.interop.JFieldMethod; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -25,43 +28,43 @@ * * @since 1.0.0 */ -class JavaField { +public class JavaField { - JFieldMethod method; - private Field field; + public JFieldMethod method; + private final Field field; - JavaField(JFieldMethod method, Field field) { + public JavaField(JFieldMethod method, Field field) { this.method = method; this.field = field; } - String getDeclaringClassName() { + public String getDeclaringClassName() { return field.getDeclaringClass().getName().replace(".", "/"); } - String getName() { + public String getName() { return field.getName(); } - boolean isStatic() { + public boolean isStatic() { return Modifier.isStatic(field.getModifiers()); } - JFieldMethod getMethod() { + public JFieldMethod getMethod() { return method; } - String getSignature() { + public String getSignature() { - return JInterop.getSig(field.getType()); + return JvmCodeGenUtil.getSig(field.getType()); } - Class getFieldType() { + public Class getFieldType() { return field.getType(); } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JavaMethodCall.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JavaMethodCall.java similarity index 97% rename from compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JavaMethodCall.java rename to compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JavaMethodCall.java index fcafe4aba516..f4899688d3c8 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/interop/JavaMethodCall.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/model/JavaMethodCall.java @@ -15,7 +15,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.wso2.ballerinalang.compiler.bir.codegen.interop; +package org.wso2.ballerinalang.compiler.bir.codegen.model; import io.ballerina.tools.diagnostics.Location; import org.wso2.ballerinalang.compiler.bir.model.BIROperand; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/optimizer/LargeMethodOptimizer.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/optimizer/LargeMethodOptimizer.java index 5167adb4782f..20aa3d646e15 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/optimizer/LargeMethodOptimizer.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/optimizer/LargeMethodOptimizer.java @@ -21,10 +21,10 @@ import org.ballerinalang.model.elements.PackageID; import org.ballerinalang.model.symbols.SymbolOrigin; import org.wso2.ballerinalang.compiler.bir.BIRGenUtils; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JInstruction; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JLargeArrayInstruction; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JLargeMapInstruction; -import org.wso2.ballerinalang.compiler.bir.codegen.interop.JMethodCallInstruction; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JInstruction; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JLargeArrayInstruction; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JLargeMapInstruction; +import org.wso2.ballerinalang.compiler.bir.codegen.model.JMethodCallInstruction; import org.wso2.ballerinalang.compiler.bir.model.BIRAbstractInstruction; import org.wso2.ballerinalang.compiler.bir.model.BIRNode; import org.wso2.ballerinalang.compiler.bir.model.BIRNode.BIRBasicBlock; @@ -79,7 +79,7 @@ public class LargeMethodOptimizer { // splits are done only if the original function has more instructions than the below number private static final int FUNCTION_INSTRUCTION_COUNT_THRESHOLD = 1000; // splits are done only if the newly created method will contain more instructions than the below number - private static final int SPLIT_INSTRUCTION_COUNT_THRESHOLD = 50; + private static final int SPLIT_INSTRUCTION_COUNT_THRESHOLD = 25; // splits are done only if the newly created method will have less function arguments than the below number private static final int MAX_SPLIT_FUNCTION_ARG_COUNT = 125; // total least no. of terminators and non-terminators that should be there to make the periodic split @@ -169,7 +169,6 @@ private void periodicSplitMap(BIRFunction parentFunc, List newlyAdd // creating necessary temp variables TempVarsForArraySplit parentFuncTempVars = getTempVarsForArraySplit(); ParentFuncEnv parentFuncEnv = new ParentFuncEnv(bbs.get(newMapInsBBNum + 1)); - BIRBasicBlock parentFuncStartBB = parentFuncEnv.parentFuncNewBB; SplitFuncEnv splitFuncEnv = new SplitFuncEnv(getTempVarsForArraySplit(), fromAttachedFunction); parentFuncEnv.returnOperand = mapIns.lhsOp; @@ -200,14 +199,13 @@ private void periodicSplitMap(BIRFunction parentFunc, List newlyAdd handleArray, handleArrayOperand, birOperands, splitFuncEnv, parentFuncEnv, mapValuesOperands, globalAndArgVarKeyOrValueLhsOperands, mapKeyOperandLocations); - setParentFuncDetails(parentFunc, bbs, newMapInsBBNum, parentFuncTempVars, parentFuncEnv, parentFuncStartBB, + setParentFuncDetails(parentFunc, bbs, newMapInsBBNum, parentFuncTempVars, parentFuncEnv, newLargeMapIns, globalAndArgVarIns); } private void setParentFuncDetails(BIRFunction parentFunc, List bbs, int newMapOrArrayInsBBNum, TempVarsForArraySplit parentFuncTempVars, ParentFuncEnv parentFuncEnv, - BIRBasicBlock parentFuncStartBB, JInstruction jLargeStructureIns, - List globalAndArgVarIns) { + JInstruction jLargeStructureIns, List globalAndArgVarIns) { parentFuncEnv.parentFuncNewInsList.addAll(globalAndArgVarIns); parentFuncEnv.parentFuncNewInsList.add(jLargeStructureIns); parentFuncEnv.parentFuncNewBB.instructions = parentFuncEnv.parentFuncNewInsList; @@ -228,7 +226,7 @@ private void setParentFuncDetails(BIRFunction parentFunc, List bb parentFunc.localVars.add(parentFuncTempVars.typeCastVarDcl); } // parent function would not have VarKind.LOCAL parentFunc.localVars. - // Hence no need to correct localVar.startBB and localVar.endBB + // Hence, no need to correct localVar.startBB and localVar.endBB } private void periodicSplitArray(BIRFunction parentFunc, List newlyAddingFunctions, @@ -242,7 +240,6 @@ private void periodicSplitArray(BIRFunction parentFunc, List newlyA // creating necessary temp variables TempVarsForArraySplit parentFuncTempVars = getTempVarsForArraySplit(); ParentFuncEnv parentFuncEnv = new ParentFuncEnv(bbs.get(newArrayInsBBNum + 1)); - BIRBasicBlock parentFuncStartBB = parentFuncEnv.parentFuncNewBB; SplitFuncEnv splitFuncEnv = new SplitFuncEnv(getTempVarsForArraySplit(), fromAttachedFunction); parentFuncEnv.returnOperand = arrayIns.lhsOp; @@ -268,7 +265,7 @@ private void periodicSplitArray(BIRFunction parentFunc, List newlyA bbs, newArrayInsBBNum, newArrayInsNumInRelevantBB, handleArray, handleArrayOperand, birOperands, splitFuncEnv, parentFuncEnv, arrayValuesOperands); - setParentFuncDetails(parentFunc, bbs, newArrayInsBBNum, parentFuncTempVars, parentFuncEnv, parentFuncStartBB, + setParentFuncDetails(parentFunc, bbs, newArrayInsBBNum, parentFuncTempVars, parentFuncEnv, newLargeArrayIns, globalAndArgVarIns); } @@ -807,9 +804,8 @@ private void createNewFuncForPeriodicSplit(BIRFunction parentFunc, List { if (changedBBs.containsKey( ((BIRTerminator.GOTO) terminator).targetBB.number)) { ((BIRTerminator.GOTO) terminator).targetBB = changedBBs.get( @@ -965,8 +961,8 @@ private void fixTerminatorBBsInPeriodicSplitFunc(SplitFuncEnv splitFuncEnv) { } ((BIRTerminator.GOTO) terminator).targetBB = beforeLastBB; } - break; - case BRANCH: + } + case BRANCH -> { BIRTerminator.Branch branchTerminator = (BIRTerminator.Branch) terminator; if (changedBBs.containsKey(branchTerminator.trueBB.number)) { branchTerminator.trueBB = changedBBs.get( @@ -976,9 +972,9 @@ private void fixTerminatorBBsInPeriodicSplitFunc(SplitFuncEnv splitFuncEnv) { branchTerminator.falseBB = changedBBs.get( branchTerminator.falseBB.number); } - break; - default: - break; + } + default -> { + } } } } @@ -1077,7 +1073,7 @@ private boolean setMapElementGivenOperand(Map possibleSplits, } } // so the next splitNum contains a split starts from this BB or another BB, but do not end in this BB + if (currentBB == null) { + throw new IllegalStateException("currentBB cannot be null"); + } changedLocalVarStartBB.put(basicBlocks.get(bbNum).id.value, currentBB.id.value); if (!splitsInSameBBList.isEmpty()) { // current unfinished BB is passed to the function and a new one is returned from it @@ -1668,9 +1667,8 @@ private BIRFunction createNewBIRFunctionAcrossBB(BIRFunction parentFunc, Name fu paramTypes.add(funcArg.type); } BInvokableType type = new BInvokableType(paramTypes, retType, null); - - BIRFunction birFunc = new BIRFunction(parentFunc.pos, funcName, funcName, 0, type, - DEFAULT_WORKER_NAME, 0, SymbolOrigin.VIRTUAL); + BIRFunction birFunc = new BIRFunction(null, funcName, funcName, 0, type, DEFAULT_WORKER_NAME, 0, + SymbolOrigin.VIRTUAL); List functionParams = new ArrayList<>(); BIRVariableDcl selfVarDcl = null; @@ -1748,12 +1746,12 @@ private void fixTerminatorBBs(int lastBBIdNum, BIRBasicBlock lastBB, BIRTerminat } switch (terminator.getKind()) { - case GOTO: + case GOTO -> { if (((BIRTerminator.GOTO) terminator).targetBB.number == lastBBIdNum) { ((BIRTerminator.GOTO) terminator).targetBB = lastBB; } - break; - case BRANCH: + } + case BRANCH -> { BIRTerminator.Branch branchTerminator = (BIRTerminator.Branch) terminator; if (branchTerminator.trueBB.number == lastBBIdNum) { branchTerminator.trueBB = lastBB; @@ -1761,9 +1759,9 @@ private void fixTerminatorBBs(int lastBBIdNum, BIRBasicBlock lastBB, BIRTerminat if (branchTerminator.falseBB.number == lastBBIdNum) { branchTerminator.falseBB = lastBB; } - break; - default: - break; + } + default -> { + } } } @@ -1786,35 +1784,33 @@ private BIRBasicBlock generateSplitsInSameBB(BIRFunction function, int bbNum, Li List newBBList, int startInsNum, BIRBasicBlock currentBB, boolean fromAttachedFunction) { List instructionList = function.basicBlocks.get(bbNum).instructions; - - for (int splitNum = 0; splitNum < possibleSplits.size(); splitNum++) { + for (Split possibleSplit : possibleSplits) { splitFuncNum += 1; String newFunctionName = SPLIT_METHOD + splitFuncNum; Name newFuncName = new Name(newFunctionName); BIROperand currentBBTerminatorLhsOp = - new BIROperand(instructionList.get(possibleSplits.get(splitNum).lastIns).lhsOp.variableDcl); - BIRFunction newBIRFunc = createNewBIRFuncForSplitInBB(function, newFuncName, - instructionList.get(possibleSplits.get(splitNum).lastIns), - instructionList.subList(possibleSplits.get(splitNum).firstIns, - possibleSplits.get(splitNum).lastIns), - possibleSplits.get(splitNum).lhsVars, possibleSplits.get(splitNum).funcArgs, fromAttachedFunction); + new BIROperand(instructionList.get(possibleSplit.lastIns).lhsOp.variableDcl); + BIRFunction newBIRFunc = createNewBIRFuncForSplitInBB(newFuncName, + instructionList.get(possibleSplit.lastIns), + instructionList.subList(possibleSplit.firstIns, possibleSplit.lastIns), + possibleSplit.lhsVars, possibleSplit.funcArgs, fromAttachedFunction); newlyAddedFunctions.add(newBIRFunc); - if (possibleSplits.get(splitNum).splitFurther) { + if (possibleSplit.splitFurther) { newlyAddedFunctions.addAll(splitBIRFunction(newBIRFunc, fromAttachedFunction, true, - possibleSplits.get(splitNum).splitTypeArray)); + possibleSplit.splitTypeArray)); } - currentBB.instructions.addAll(instructionList.subList(startInsNum, possibleSplits.get(splitNum).firstIns)); - startInsNum = possibleSplits.get(splitNum).lastIns + 1; + currentBB.instructions.addAll(instructionList.subList(startInsNum, possibleSplit.firstIns)); + startInsNum = possibleSplit.lastIns + 1; newBBNum += 1; BIRBasicBlock newBB = new BIRBasicBlock(newBBNum); List args = new ArrayList<>(); - for (BIRVariableDcl funcArg : possibleSplits.get(splitNum).funcArgs) { + for (BIRVariableDcl funcArg : possibleSplit.funcArgs) { args.add(new BIROperand(funcArg)); } - currentBB.terminator = new BIRTerminator.Call(instructionList.get(possibleSplits.get(splitNum).lastIns).pos, + currentBB.terminator = new BIRTerminator.Call(instructionList.get(possibleSplit.lastIns).pos, InstructionKind.CALL, false, currentPackageId, newFuncName, args, currentBBTerminatorLhsOp, newBB, Collections.emptyList(), Collections.emptySet(), - instructionList.get(possibleSplits.get(splitNum).lastIns).scope); + instructionList.get(possibleSplit.lastIns).scope); newBBList.add(currentBB); currentBB = newBB; } @@ -1856,7 +1852,6 @@ private BIROperand generateTempLocalVariable(BType variableType, Set collectedIns, Set lhsOperandList, List funcArgs, boolean fromAttachedFunction) { @@ -1875,9 +1870,8 @@ private BIRFunction createNewBIRFuncForSplitInBB(BIRFunction parentFunc, Name fu paramTypes.add(funcArg.type); } BInvokableType type = new BInvokableType(paramTypes, retType, null); - - BIRFunction birFunc = new BIRFunction(parentFunc.pos, funcName, funcName, 0, type, - DEFAULT_WORKER_NAME, 0, SymbolOrigin.VIRTUAL); + BIRFunction birFunc = new BIRFunction(null, funcName, funcName, 0, type, DEFAULT_WORKER_NAME, 0, + SymbolOrigin.VIRTUAL); List functionParams = new ArrayList<>(); BIRVariableDcl selfVarDcl = null; diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/JvmAnnotationsGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/JvmAnnotationsGen.java index 0e1d6f77df30..cde5f6a01cab 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/JvmAnnotationsGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/JvmAnnotationsGen.java @@ -22,6 +22,7 @@ import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.wso2.ballerinalang.compiler.bir.codegen.BallerinaClassWriter; +import org.wso2.ballerinalang.compiler.bir.codegen.JarEntries; import org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil; import org.wso2.ballerinalang.compiler.bir.codegen.JvmPackageGen; import org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures; @@ -32,7 +33,6 @@ import org.wso2.ballerinalang.util.Flags; import java.util.List; -import java.util.Map; import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; import static org.objectweb.asm.Opcodes.ACC_PUBLIC; @@ -62,19 +62,16 @@ public class JvmAnnotationsGen { private final String annotationsClass; private final JvmPackageGen jvmPackageGen; private final JvmTypeGen jvmTypeGen; - private final JvmConstantsGen jvmConstantsGen; private final BIRNode.BIRPackage module; - public JvmAnnotationsGen(BIRNode.BIRPackage module, JvmPackageGen jvmPackageGen, JvmTypeGen jvmTypeGen, - JvmConstantsGen jvmConstantsGen) { + public JvmAnnotationsGen(BIRNode.BIRPackage module, JvmPackageGen jvmPackageGen, JvmTypeGen jvmTypeGen) { this.annotationsClass = getModuleLevelClassName(module.packageID, MODULE_ANNOTATIONS_CLASS_NAME); this.jvmPackageGen = jvmPackageGen; this.jvmTypeGen = jvmTypeGen; this.module = module; - this.jvmConstantsGen = jvmConstantsGen; } - public void generateAnnotationsClass(Map jarEntries) { + public void generateAnnotationsClass(JarEntries jarEntries) { ClassWriter cw = new BallerinaClassWriter(COMPUTE_FRAMES); cw.visit(V17, ACC_PUBLIC + ACC_SUPER, annotationsClass, null, OBJECT, null); generateProcessAnnotationsMethod(cw, module.typeDefs, module.packageID); @@ -126,7 +123,7 @@ private int generateAnnotationsLoad(ClassWriter cw, List jarEntries) { + public void generateConstants(JarEntries jarEntries, Map strandMetadata) { jvmBallerinaConstantsGen.generateConstantInit(jarEntries); unionTypeConstantsGen.generateClass(jarEntries); errorTypeConstantsGen.generateClass(jarEntries); @@ -104,6 +110,7 @@ public void generateConstants(Map jarEntries) { stringConstantsGen.generateConstantInit(jarEntries); tupleTypeConstantsGen.generateClass(jarEntries); arrayTypeConstantsGen.generateClass(jarEntries); + strandMetadataConstantsGen.generateClass(jarEntries, strandMetadata); refTypeConstantsGen.generateClass(jarEntries); } @@ -119,23 +126,14 @@ public void generateGetBTupleType(MethodVisitor mv, String varName) { tupleTypeConstantsGen.generateGetBTupleType(mv, varName); } - public void generateGetBTypeRefType(MethodVisitor mv, String varName) { - refTypeConstantsGen.generateGetBTypeRefType(mv, varName); - } - public String getTypeConstantsVar(BType type, SymbolTable symbolTable) { - switch (type.tag) { - case TypeTags.ERROR: - return errorTypeConstantsGen.add((BErrorType) type); - case TypeTags.ARRAY: - return arrayTypeConstantsGen.add((BArrayType) type); - case TypeTags.TUPLE: - return tupleTypeConstantsGen.add((BTupleType) type, symbolTable); - case TypeTags.TYPEREFDESC: - return refTypeConstantsGen.add((BTypeReferenceType) type); - default: - return unionTypeConstantsGen.add((BUnionType) type, symbolTable); - } + return switch (type.tag) { + case TypeTags.ERROR -> errorTypeConstantsGen.add((BErrorType) type); + case TypeTags.ARRAY -> arrayTypeConstantsGen.add((BArrayType) type); + case TypeTags.TUPLE -> tupleTypeConstantsGen.add((BTupleType) type, symbolTable); + case TypeTags.TYPEREFDESC -> refTypeConstantsGen.add((BTypeReferenceType) type); + default -> unionTypeConstantsGen.add((BUnionType) type, symbolTable); + }; } public String getStringConstantsClass() { @@ -170,6 +168,10 @@ public String getConstantClass() { return jvmBallerinaConstantsGen.getConstantClass(); } + public String getStrandMetadataConstantsClass() { + return strandMetadataConstantsGen.getStrandMetadataConstantsClass(); + } + public void generateGetBArrayType(MethodVisitor mv, String varName) { arrayTypeConstantsGen.generateGetBArrayType(mv, varName); } diff --git a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/JvmCreateTypeGen.java b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/JvmCreateTypeGen.java index e1c2b78ee807..dd383de6ed93 100644 --- a/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/JvmCreateTypeGen.java +++ b/compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/bir/codegen/split/JvmCreateTypeGen.java @@ -23,6 +23,7 @@ import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.wso2.ballerinalang.compiler.bir.codegen.BallerinaClassWriter; +import org.wso2.ballerinalang.compiler.bir.codegen.JarEntries; import org.wso2.ballerinalang.compiler.bir.codegen.JvmCodeGenUtil; import org.wso2.ballerinalang.compiler.bir.codegen.JvmPackageGen; import org.wso2.ballerinalang.compiler.bir.codegen.JvmSignatures; @@ -173,7 +174,7 @@ public JvmCreateTypeGen(JvmTypeGen jvmTypeGen, JvmConstantsGen jvmConstantsGen, } public void generateTypeClass(JvmPackageGen jvmPackageGen, BIRNode.BIRPackage module, - Map jarEntries, + JarEntries jarEntries, String moduleInitClass, SymbolTable symbolTable) { generateCreateTypesMethod(typesCw, module.typeDefs, moduleInitClass, symbolTable); typesCw.visitEnd(); @@ -279,21 +280,13 @@ private int createTypesInstanceSplits(ClassWriter cw, List ty } } switch (bTypeTag) { - case TypeTags.RECORD: - jvmRecordTypeGen.createRecordType(mv, (BRecordType) bType, typeOwnerClass, name); - break; - case TypeTags.OBJECT: - jvmObjectTypeGen.createObjectType(mv, (BObjectType) bType); - break; - case TypeTags.ERROR: - jvmErrorTypeGen.createErrorType(mv, (BErrorType) bType, bType.tsymbol.name.value); - break; - case TypeTags.TUPLE: - jvmTupleTypeGen.createTupleType(mv, (BTupleType) bType); - break; - default: - jvmUnionTypeGen.createUnionType(mv, (BUnionType) bType); - break; + case TypeTags.RECORD -> + jvmRecordTypeGen.createRecordType(mv, (BRecordType) bType, typeOwnerClass, name); + case TypeTags.OBJECT -> jvmObjectTypeGen.createObjectType(mv, (BObjectType) bType); + case TypeTags.ERROR -> + jvmErrorTypeGen.createErrorType(mv, (BErrorType) bType, bType.tsymbol.name.value); + case TypeTags.TUPLE -> jvmTupleTypeGen.createTupleType(mv, (BTupleType) bType); + default -> jvmUnionTypeGen.createUnionType(mv, (BUnionType) bType); } mv.visitFieldInsn(PUTSTATIC, typeOwnerClass, getTypeFieldName(name), GET_TYPE); @@ -329,35 +322,35 @@ private Map populateTypes(ClassWriter cw, List { funcTypeClassMap.put(methodName, jvmRecordTypeGen.recordTypesClass); mv = createPopulateTypeMethod(jvmRecordTypeGen.recordTypesCw, methodName, typeOwnerClass, fieldName); jvmRecordTypeGen.populateRecord(mv, methodName, (BRecordType) bType, symbolTable); - break; - case TypeTags.OBJECT: + } + case TypeTags.OBJECT -> { funcTypeClassMap.put(methodName, jvmObjectTypeGen.objectTypesClass); mv = createPopulateTypeMethod(jvmObjectTypeGen.objectTypesCw, methodName, typeOwnerClass, fieldName); jvmObjectTypeGen.populateObject(cw, mv, methodName, symbolTable, fieldName, (BObjectType) bType, new BIRVarToJVMIndexMap()); - break; - case TypeTags.ERROR: + } + case TypeTags.ERROR -> { // populate detail field funcTypeClassMap.put(methodName, jvmErrorTypeGen.errorTypesClass); mv = createPopulateTypeMethod(jvmErrorTypeGen.errorTypesCw, methodName, typeOwnerClass, fieldName); jvmErrorTypeGen.populateError(mv, (BErrorType) bType); - break; - case TypeTags.TUPLE: + } + case TypeTags.TUPLE -> { funcTypeClassMap.put(methodName, jvmTupleTypeGen.tupleTypesClass); mv = createPopulateTypeMethod(jvmTupleTypeGen.tupleTypesCw, methodName, typeOwnerClass, fieldName); jvmTupleTypeGen.populateTuple(mv, (BTupleType) bType, symbolTable); - break; - default: + } + default -> { funcTypeClassMap.put(methodName, jvmUnionTypeGen.unionTypesClass); mv = createPopulateTypeMethod(jvmUnionTypeGen.unionTypesCw, methodName, typeOwnerClass, fieldName); jvmUnionTypeGen.populateUnion(cw, mv, (BUnionType) bType, typesClass, fieldName, symbolTable); - break; + } } mv.visitInsn(RETURN); @@ -494,7 +487,7 @@ public static List